namei: Calculate offset before use in GetFreeTag
[openafs.git] / src / vol / namei_ops.c
index bae4039..f9dd4e5 100644 (file)
@@ -64,7 +64,6 @@
 #ifdef AFS_SALSRV_ENV
 #include <pthread.h>
 #include <afs/work_queue.h>
-#include <afs/thread_pool.h>
 #include <vol/vol-salvage.h>
 #endif
 
@@ -326,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,
@@ -338,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);
 }
@@ -835,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;
@@ -954,20 +959,21 @@ bad:
 #else /* !AFS_NT40_ENV */
 Inode
 icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
-        FD_t *afd, Inode *ainode)
+        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) {
@@ -1035,14 +1041,19 @@ icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3,
        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);
     }
 
+    FDH_CLOSE(fdP);
+
   bad:
     if (code || (fd == INVALID_FD)) {
        if (p2 != -1) {
@@ -1052,10 +1063,10 @@ icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3,
                FDH_CLOSE(fdP);
            }
        }
+       IH_RELEASE(realh);
     }
 
-    *afd = fd;
-    *ainode = tmp.ih_ino;
+    *a_ih = realh;
 
     return code;
 }
@@ -1064,44 +1075,32 @@ Inode
 namei_icreate(IHandle_t * lh, char *part,
               afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
 {
-    Inode ino = 0;
-    int fd = INVALID_FD;
+    Inode ino;
+    IHandle_t *ihP = NULL;
     int code;
 
-    code = icreate(lh, part, p1, p2, p3, p4, &fd, &ino);
-    if (fd != INVALID_FD) {
-       close(fd);
+    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 (code || (fd == INVALID_FD)) ? (Inode) - 1 : ino;
+    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)
 {
-    Inode ino = 0;
-    int fd = INVALID_FD;
     int code;
-    IHandle_t *ihP;
-    FdHandle_t *fdP;
+    IHandle_t *ihP = NULL;
 
-    code = icreate(lh, part, p1, p2, p3, p4, &fd, &ino);
-    if (fd == INVALID_FD) {
-       return NULL;
-    }
+    code = icreate(lh, part, p1, p2, p3, p4, &ihP);
     if (code) {
-       close(fd);
-       return NULL;
-    }
-
-    IH_INIT(ihP, dev, p1, ino);
-    fdP = ih_attachfd(ihP, fd);
-    if (!fdP) {
-       close(fd);
-    } else {
-       FDH_CLOSE(fdP);
+       opr_Assert(!ihP);
     }
-
     return ihP;
 }
 #endif
@@ -1182,6 +1181,15 @@ namei_dec(IHandle_t * ih, Inode ino, int p1)
            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.
@@ -1195,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);
@@ -1314,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;
@@ -1569,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;
@@ -1604,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)
@@ -1626,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)
@@ -2605,8 +2608,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))) {
@@ -2614,13 +2623,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))) {
@@ -3128,8 +3146,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",
@@ -3159,8 +3182,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);
@@ -3172,14 +3200,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);
@@ -3191,7 +3228,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
 
@@ -3218,6 +3259,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) {
@@ -3329,4 +3371,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 */