vol: Blank fake linkHandles
[openafs.git] / src / vol / namei_ops.c
index c48c1b2..463b66b 100644 (file)
 #ifdef AFS_SALSRV_ENV
 #include <pthread.h>
 #include <afs/work_queue.h>
-#include <afs/thread_pool.h>
 #include <vol/vol-salvage.h>
 #endif
 
 int Testing=0;
 
+static void namei_UnlockLinkCount(FdHandle_t * fdP, Inode ino);
 
 afs_sfsize_t
 namei_iread(IHandle_t * h, afs_foff_t offset, char *buf, afs_fsize_t size)
@@ -325,7 +325,7 @@ int
 namei_ViceREADME(char *partition)
 {
     char filename[32];
-    int fd;
+    int fd, len, e = 0;
 
     /* Create the inode directory if we're starting for the first time */
     snprintf(filename, sizeof filename, "%s" OS_DIRSEP "%s", partition,
@@ -337,8 +337,12 @@ namei_ViceREADME(char *partition)
              partition, INODEDIR);
     fd = OS_OPEN(filename, O_WRONLY | O_CREAT | O_TRUNC, 0444);
     if (fd != INVALID_FD) {
-       (void)OS_WRITE(fd, VICE_README, strlen(VICE_README));
+       len = strlen(VICE_README);
+       if (OS_WRITE(fd, VICE_README, len) != len)
+           e = errno;
        OS_CLOSE(fd);
+       if (e)
+           errno = e;
     }
     return (errno);
 }
@@ -834,6 +838,8 @@ namei_icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint
     memset((void *)&tmp, 0, sizeof(IHandle_t));
     memset(&tfd, 0, sizeof(FdHandle_t));
 
+    ih_PkgDefaults();
+
     tmp.ih_dev = nt_DriveToDev(part);
     if (tmp.ih_dev == -1) {
        errno = EINVAL;
@@ -952,20 +958,22 @@ bad:
 }
 #else /* !AFS_NT40_ENV */
 Inode
-namei_icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
+icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
+        IHandle_t **a_ih)
 {
     namei_t name;
     int fd = INVALID_FD;
     int code = 0;
     int created_dir = 0;
     IHandle_t tmp;
+    IHandle_t *realh = NULL;
     FdHandle_t *fdP;
-    FdHandle_t tfd;
     int tag;
     int ogm_parm;
 
     memset((void *)&tmp, 0, sizeof(IHandle_t));
-    memset(&tfd, 0, sizeof(FdHandle_t));
+
+    ih_PkgDefaults();
 
     tmp.ih_dev = volutil_GetPartitionID(part);
     if (tmp.ih_dev == -1) {
@@ -1033,19 +1041,20 @@ namei_icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint
        goto bad;
     }
 
+    IH_INIT(realh, tmp.ih_dev, tmp.ih_vid, tmp.ih_ino);
+    fdP = ih_attachfd(realh, fd);
+
+    /* ih_attachfd can only return NULL if we give it an invalid fd; our fd
+     * must be valid by this point. */
+    opr_Assert(fdP);
+
     if (p2 == (afs_uint32)-1 && p3 == VI_LINKTABLE) {
-       /* hack at tmp to setup for set link count call. */
-       memset((void *)&tfd, 0, sizeof(FdHandle_t));    /* minimalistic still, but a little cleaner */
-       tfd.fd_ih = &tmp;
-       tfd.fd_fd = fd;
-       code = namei_SetLinkCount(&tfd, (Inode) 0, 1, 0);
+       code = namei_SetLinkCount(fdP, (Inode) 0, 1, 0);
     }
 
-  bad:
-    if (fd != INVALID_FD)
-       OS_CLOSE(fd);
-
+    FDH_CLOSE(fdP);
 
+  bad:
     if (code || (fd == INVALID_FD)) {
        if (p2 != -1) {
            fdP = IH_OPEN(lh);
@@ -1054,8 +1063,45 @@ namei_icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint
                FDH_CLOSE(fdP);
            }
        }
+       IH_RELEASE(realh);
     }
-    return (code || (fd == INVALID_FD)) ? (Inode) - 1 : tmp.ih_ino;
+
+    *a_ih = realh;
+
+    return code;
+}
+
+Inode
+namei_icreate(IHandle_t * lh, char *part,
+              afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
+{
+    Inode ino;
+    IHandle_t *ihP = NULL;
+    int code;
+
+    code = icreate(lh, part, p1, p2, p3, p4, &ihP);
+    if (code || !ihP) {
+       opr_Assert(!ihP);
+       ino = -1;
+    } else {
+       ino = ihP->ih_ino;
+       IH_RELEASE(ihP);
+    }
+    return ino;
+}
+
+IHandle_t *
+namei_icreate_init(IHandle_t * lh, int dev, char *part,
+                   afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
+{
+    int code;
+    IHandle_t *ihP = NULL;
+
+    code = icreate(lh, part, p1, p2, p3, p4, &ihP);
+    if (code) {
+       opr_Assert(!ihP);
+    }
+    return ihP;
 }
 #endif
 
@@ -1116,20 +1162,34 @@ namei_dec(IHandle_t * ih, Inode ino, int p1)
            }
 
            count--;
-           if (namei_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) <
-               0) {
-               FDH_REALLYCLOSE(fdP);
-               IH_RELEASE(tmp);
-               return -1;
-           }
-
            if (count > 0) {
+               /* if our count is non-zero, we just set our new linkcount and
+                * return. But if our count is 0, don't bother updating the
+                * linktable, since we're about to delete the link table,
+                * below. */
+               if (namei_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) < 0) {
+                   FDH_REALLYCLOSE(fdP);
+                   IH_RELEASE(tmp);
+                   return -1;
+               }
+
                FDH_CLOSE(fdP);
                IH_RELEASE(tmp);
                return 0;
            }
+
+           namei_UnlockLinkCount(fdP, (Inode) 0);
        }
 
+       /* We should IH_REALLYCLOSE right before deleting the special file from
+        * disk, to ensure that somebody else cannot create a special inode,
+        * then IH_OPEN that special inode and get back a cached fd for the
+        * file we are deleting here (instead of an fd for the file they just
+        * created). */
+       IH_REALLYCLOSE(tmp);
+       FDH_REALLYCLOSE(fdP);
+       IH_RELEASE(tmp);
+
        if ((code = OS_UNLINK(name.n_path)) == 0) {
            if (type == VI_LINKTABLE) {
                /* Try to remove directory. If it fails, that's ok.
@@ -1143,8 +1203,6 @@ namei_dec(IHandle_t * ih, Inode ino, int p1)
                (void)namei_RemoveDataDirectories(&name);
            }
        }
-       FDH_REALLYCLOSE(fdP);
-       IH_RELEASE(tmp);
     } else {
        /* Get a file descriptor handle for this Inode */
        fdP = IH_OPEN(ih);
@@ -1262,7 +1320,7 @@ namei_copy_on_write(IHandle_t *h)
     if (afs_stat(name.n_path, &tstat) < 0)
        return EIO;
     if (tstat.st_nlink > 1) {                   /* do a copy on write */
-       char path[259];
+       char path[NAMEI_PATH_LEN + 4];
        char *buf;
        afs_size_t size;
        ssize_t tlen;
@@ -1517,7 +1575,10 @@ namei_GetLinkCount(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrite
            NAMEI_GLC_UNLOCK;
            goto bad_getLinkByte;
        }
-        FDH_TRUNC(h, offset+sizeof(row));
+        if (FDH_TRUNC(h, offset+sizeof(row))) {
+           NAMEI_GLC_UNLOCK;
+           goto bad_getLinkByte;
+       }
         row = 1 << index;
        rc = FDH_PWRITE(h, (char *)&row, sizeof(row), offset);
        NAMEI_GLC_UNLOCK;
@@ -1552,12 +1613,6 @@ namei_GetLinkCount(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrite
     return -1;
 }
 
-int
-namei_SetNonZLC(FdHandle_t * h, Inode ino)
-{
-    return namei_GetLinkCount(h, ino, 0, 1, 0);
-}
-
 /* Return a free column index for this vnode. */
 static int
 GetFreeTag(IHandle_t * ih, int vno)
@@ -1574,14 +1629,14 @@ GetFreeTag(IHandle_t * ih, int vno)
     if (fdP == NULL)
        return -1;
 
+    offset = (vno << LINKTABLE_SHIFT) + 8;     /* * 2 + sizeof stamp */
+
     /* Only one manipulates at a time. */
     if (FDH_LOCKFILE(fdP, offset) != 0) {
        FDH_REALLYCLOSE(fdP);
        return -1;
     }
 
-    offset = (vno << LINKTABLE_SHIFT) + 8;     /* * 2 + sizeof stamp */
-
     nBytes = FDH_PREAD(fdP, (char *)&row, sizeof(row), offset);
     if (nBytes != sizeof(row)) {
        if (nBytes != 0)
@@ -1670,10 +1725,21 @@ namei_SetLinkCount(FdHandle_t * fdP, Inode ino, int count, int locked)
     return (int)nBytes;
 }
 
+static void
+namei_UnlockLinkCount(FdHandle_t * fdP, Inode ino)
+{
+    afs_foff_t offset;
+    int index;
+
+    namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
+
+    FDH_UNLOCKFILE(fdP, offset);
+}
+
 
 /* ListViceInodes - write inode data to a results file. */
 static int DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
-                      VolumeId volid);
+                      IHandle_t *myIH);
 static int DecodeVolumeName(char *name, VolumeId *vid);
 static int namei_ListAFSSubDirs(IHandle_t * dirIH,
                                int (*write_fun) (FD_t,
@@ -1936,7 +2002,7 @@ _namei_examine_special(char * path1,
     int ret = 0;
     struct ViceInodeInfo info;
 
-    if (DecodeInode(path1, dname, &info, myIH->ih_vid) < 0) {
+    if (DecodeInode(path1, dname, &info, myIH) < 0) {
        ret = 0;
        goto error;
     }
@@ -1951,6 +2017,11 @@ _namei_examine_special(char * path1,
            "(dir_vgid=%" AFS_VOLID_FMT ", inode_vgid=%" AFS_VOLID_FMT ")\n",
            path1, dname, afs_printable_VolumeId_lu(myIH->ih_vid),
            afs_printable_VolumeId_lu(info.u.param[0]));
+       /* We need to set the linkCount to _something_, so linkCount
+        * doesn't just contain stack garbage. Set it to 0, so in case
+        * the salvager or whatever our caller is does try to process
+        * this like a normal file, we won't try to INC or DEC it. */
+       info.linkCount = 0;
     } else {
        char path2[512];
        /* Open this handle */
@@ -2022,7 +2093,7 @@ _namei_examine_reg(char * path3,
     int dirl; /* Windows-only (one level hash dir) */
 #endif
 
-    if (DecodeInode(path3, dname, &info, myIH->ih_vid) < 0) {
+    if (DecodeInode(path3, dname, &info, myIH) < 0) {
        goto error;
     }
 
@@ -2434,6 +2505,8 @@ namei_ListAFSSubDirs(IHandle_t * dirIH,
     struct rx_queue resultlist;
 #endif
 
+    memset(&linkHandle, 0, sizeof(linkHandle));
+
     namei_HandleToVolDir(&name, &myIH);
     strlcpy(path1, name.n_path, sizeof(path1));
 
@@ -2537,8 +2610,14 @@ namei_ListAFSSubDirs(IHandle_t * dirIH,
 
 #ifndef AFS_NT40_ENV /* This level missing on Windows */
            /* Now we've got a next level subdir. */
-           snprintf(path2, sizeof(path2), "%s" OS_DIRSEP "%s",
-                    path1, dp1->d_name);
+           code = snprintf(path2, sizeof(path2), "%s" OS_DIRSEP "%s",
+                           path1, dp1->d_name);
+           if (code < 0 || code >= sizeof(path2)) {
+               /* error, or truncated */
+               closedir(dirp1);
+               ret = -1;
+               goto error;
+           }
            dirp2 = opendir(path2);
            if (dirp2) {
                while ((dp2 = readdir(dirp2))) {
@@ -2546,13 +2625,22 @@ namei_ListAFSSubDirs(IHandle_t * dirIH,
                        continue;
 
                    /* Now we've got to the actual data */
-                   snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
-                            path2, dp2->d_name);
+                   code = snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
+                                   path2, dp2->d_name);
 #else
                    /* Now we've got to the actual data */
-                   snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
-                            path1, dp1->d_name);
+                   code = snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
+                                   path1, dp1->d_name);
 #endif
+                   if (code < 0 || code >= sizeof(path3)) {
+                       /* error, or truncated */
+#ifndef AFS_NT40_ENV
+                       closedir(dirp2);
+#endif
+                       closedir(dirp1);
+                       ret = -1;
+                       goto error;
+                   }
                    dirp3 = opendir(path3);
                    if (dirp3) {
                        while ((dp3 = readdir(dirp3))) {
@@ -2681,7 +2769,7 @@ DecodeVolumeName(char *name, VolumeId *vid)
 #ifdef AFS_NT40_ENV
 static int
 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
-           VolumeId volid)
+           IHandle_t *myIH)
 {
     char fpath[512];
     int tag, vno;
@@ -2691,6 +2779,9 @@ DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
     char stmp[16];
     FdHandle_t linkHandle;
     char dirl;
+    VolumeId volid = myIH->ih_vid;
+
+    memset(&linkHandle, 0, sizeof(linkHandle));
 
     snprintf(fpath, sizeof(fpath), "%s" OS_DIRSEP "%s", dpath, name);
 
@@ -2757,12 +2848,16 @@ DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
 #else
 static int
 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
-           VolumeId volid)
+           IHandle_t *myIH)
 {
     char fpath[512];
     struct afs_stat_st status;
+    struct afs_stat_st checkstatus;
     int parm, tag;
     lb64_string_t check;
+    VolumeId volid = myIH->ih_vid;
+    IHandle_t tmpih;
+    namei_t nameiname;
 
     snprintf(fpath, sizeof(fpath), "%s" OS_DIRSEP "%s", dpath, name);
 
@@ -2777,6 +2872,36 @@ DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
     if (strcmp(name, check))
        return -1;
 
+    /* Check if the _full_ path is correct, to ensure we can actually open this
+     * file later. Otherwise, the salvager can choke. */
+    memset(&tmpih, 0, sizeof(tmpih));
+    tmpih.ih_dev = myIH->ih_dev;
+    tmpih.ih_vid = myIH->ih_vid;
+    tmpih.ih_ino = info->inodeNumber;
+    namei_HandleToName(&nameiname, &tmpih);
+    if ((afs_stat(nameiname.n_path, &checkstatus) < 0) ||
+        checkstatus.st_ino != status.st_ino ||
+        checkstatus.st_size != status.st_size) {
+       static int logged;
+       /* log something for this case, since this means the filename looks
+        * like a valid inode, but it's just in the wrong place. That's pretty
+        * strange. */
+       if (!logged) {
+           logged = 1;
+           Log("Note:\n");
+           Log("  Seemingly-misplaced files have been found, which I am\n");
+           Log("  ignoring for now. If you cannot salvage the relevant volume,\n");
+           Log("  you may try manually moving them to their correct location.\n");
+           Log("  If the relevant volume seems fine, and these files do not\n");
+           Log("  appear to contain important data, you can probably manually\n");
+           Log("  delete them, or leave them alone. Contact your local OpenAFS\n");
+           Log("  expert if you are unsure.\n");
+       }
+       Log("Ignoring misplaced file in volume group %u: %s (should be %s)\n",
+           (unsigned)myIH->ih_vid, fpath, nameiname.n_path);
+       return -1;
+    }
+
     if ((info->inodeNumber & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
        parm = ((info->inodeNumber >> NAMEI_UNIQSHIFT) & NAMEI_UNIQMASK);
        tag = (int)((info->inodeNumber >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
@@ -2965,7 +3090,7 @@ namei_ConvertROtoRWvolume(char *pname, VolumeId volumeId)
        if (*dp->d_name == '.')
            continue;
 #endif
-       if (DecodeInode(dir_name, dp->d_name, &info, ih->ih_vid) < 0) {
+       if (DecodeInode(dir_name, dp->d_name, &info, ih) < 0) {
            Log("1 namei_ConvertROtoRWvolume: DecodeInode failed for %s" OS_DIRSEP "%s\n",
                dir_name, dp->d_name);
            closedir(dirp);
@@ -3025,8 +3150,13 @@ namei_ConvertROtoRWvolume(char *pname, VolumeId volumeId)
     t_ih.ih_dev = ih->ih_dev;
     t_ih.ih_vid = ih->ih_vid;
 
-    snprintf(oldpath, sizeof oldpath, "%s" OS_DIRSEP "%s", dir_name,
-            infoName);
+    code = snprintf(oldpath, sizeof oldpath, "%s" OS_DIRSEP "%s", dir_name,
+                   infoName);
+    if (code < 0 || code >= sizeof(oldpath)) {
+       /* error, or truncated */
+       code = -1;
+       goto done;
+    }
     fd = OS_OPEN(oldpath, O_RDWR, 0);
     if (fd == INVALID_FD) {
        Log("1 namei_ConvertROtoRWvolume: could not open RO info file: %s\n",
@@ -3056,8 +3186,13 @@ namei_ConvertROtoRWvolume(char *pname, VolumeId volumeId)
 
     t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_SMALLINDEX);
     namei_HandleToName(&n, &t_ih);
-    snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
-            smallName);
+    code = snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
+                   smallName);
+    if (code < 0 || code >= sizeof(newpath)) {
+       /* error, or truncated */
+       code = -1;
+       goto done;
+    }
     fd = OS_OPEN(newpath, O_RDWR, 0);
     if (fd == INVALID_FD) {
        Log("1 namei_ConvertROtoRWvolume: could not open SmallIndex file: %s\n", newpath);
@@ -3069,14 +3204,23 @@ namei_ConvertROtoRWvolume(char *pname, VolumeId volumeId)
 #ifdef AFS_NT40_ENV
     MoveFileEx(n.n_path, newpath, MOVEFILE_WRITE_THROUGH);
 #else
-    link(newpath, n.n_path);
+    if (link(newpath, n.n_path)) {
+       Log("1 namei_ConvertROtoRWvolume: could not move SmallIndex file: %s\n", n.n_path);
+       code = -1;
+       goto done;
+    }
     OS_UNLINK(newpath);
 #endif
 
     t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_LARGEINDEX);
     namei_HandleToName(&n, &t_ih);
-    snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
-            largeName);
+    code = snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
+                   largeName);
+    if (code < 0 || code >= sizeof(newpath)) {
+       /* error, or truncated */
+       code = -1;
+       goto done;
+    }
     fd = OS_OPEN(newpath, O_RDWR, 0);
     if (fd == INVALID_FD) {
        Log("1 namei_ConvertROtoRWvolume: could not open LargeIndex file: %s\n", newpath);
@@ -3088,7 +3232,11 @@ namei_ConvertROtoRWvolume(char *pname, VolumeId volumeId)
 #ifdef AFS_NT40_ENV
     MoveFileEx(n.n_path, newpath, MOVEFILE_WRITE_THROUGH);
 #else
-    link(newpath, n.n_path);
+    if (link(newpath, n.n_path)) {
+       Log("1 namei_ConvertROtoRWvolume: could not move LargeIndex file: %s\n", n.n_path);
+       code = -1;
+       goto done;
+    }
     OS_UNLINK(newpath);
 #endif
 
@@ -3115,6 +3263,7 @@ namei_ConvertROtoRWvolume(char *pname, VolumeId volumeId)
     FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
     FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
 
+    code = 0;
  done:
 # ifdef AFS_DEMAND_ATTACH_FS
     if (locktype) {
@@ -3226,4 +3375,37 @@ FreeZLCList(void)
 }
 #endif
 
+/**
+ * Remove empty directories associated with the volume received
+ * as an argument.
+ *
+ * @param[in] pname    vice partition path
+ * @param[in] vid      volume id
+ *
+ * @return 0 on success
+ */
+int
+namei_RemoveDirectories(char *pname, afs_int32 vid)
+{
+    IHandle_t dirIH;
+    namei_t name;
+
+    memset(&dirIH, 0, sizeof(dirIH));
+
+    dirIH.ih_vid = vid;
+
+#ifdef AFS_NT40_ENV
+    dirIH.ih_dev = nt_DriveToDev(pname);
+#else
+    dirIH.ih_dev = volutil_GetPartitionID(pname);
+#endif
+    if (dirIH.ih_dev == -1) {
+       return -1;
+    }
+
+    namei_HandleToVolDir(&name, &dirIH);
+
+    return namei_RemoveDataDirectories(&name);
+}
+
 #endif /* AFS_NAMEI_ENV */