dir: check afs_dir_Create return code in afs_dir_MakeDir
[openafs.git] / src / dir / dir.c
index 6db96b2..0fb6bff 100644 (file)
 #   include "h/user.h"
 #  endif /* AFS_SGI64_ENV */
 #  include "h/uio.h"
-#  ifdef       AFS_OSF_ENV
-#   include <sys/mount.h>
-#   include <sys/vnode.h>
-#   include <ufs/inode.h>
-#  endif
 #  if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_HPUX110_ENV)
 #   include "h/mbuf.h"
 #  endif
@@ -75,8 +70,6 @@ extern int DNew(struct dcache *adc, int page, struct DirBuffer *);
 # include "dir.h"
 #endif /* KERNEL */
 
-afs_int32 DErrno;
-
 /* Local static prototypes */
 static int FindBlobs(dir_file_t, int);
 static void AddPage(dir_file_t, int);
@@ -104,13 +97,18 @@ afs_dir_Create(dir_file_t dir, char *entry, void *voidfid)
     struct DirBuffer entrybuf, prevbuf, headerbuf;
     struct DirEntry *ep;
     struct DirHeader *dhp;
+    int code;
 
     /* check name quality */
     if (*entry == 0)
        return EINVAL;
 
     /* First check if file already exists. */
-    if (FindItem(dir, entry, &prevbuf, &entrybuf) == 0) {
+    code = FindItem(dir, entry, &prevbuf, &entrybuf);
+    if (code && code != ENOENT) {
+        return code;
+    }
+    if (code == 0) {
        DRelease(&entrybuf, 0);
        DRelease(&prevbuf, 0);
        return EEXIST;
@@ -180,9 +178,12 @@ afs_dir_Delete(dir_file_t dir, char *entry)
     struct DirBuffer entrybuf, prevbuf;
     struct DirEntry *firstitem;
     unsigned short *previtem;
+    int code;
 
-    if (FindItem(dir, entry, &prevbuf, &entrybuf) != 0)
-       return ENOENT;
+    code = FindItem(dir, entry, &prevbuf, &entrybuf);
+    if (code) {
+        return code;
+    }
 
     firstitem = (struct DirEntry *)entrybuf.data;
     previtem = (unsigned short *)prevbuf.data;
@@ -325,10 +326,17 @@ FreeBlobs(dir_file_t dir, int firstblob, int nblobs)
     DRelease(&pagehdbuf, 1);
 }
 
-/*
+/*!
  * Format an empty directory properly.  Note that the first 13 entries in a
  * directory header page are allocated, 1 to the page header, 4 to the
  * allocation map and 8 to the hash table.
+ *
+ * \param dir      pointer to the directory object
+ * \param me       fid (vnode+uniq) for new dir
+ * \param parent    fid (vnode+uniq) for parent dir
+ *
+ * \retval 0       success
+ * \retval nonzero  error code
  */
 int
 afs_dir_MakeDir(dir_file_t dir, afs_int32 * me, afs_int32 * parent)
@@ -336,6 +344,7 @@ afs_dir_MakeDir(dir_file_t dir, afs_int32 * me, afs_int32 * parent)
     int i;
     struct DirBuffer buffer;
     struct DirHeader *dhp;
+    int code;
 
     DNew(dir, 0, &buffer);
     dhp = (struct DirHeader *)buffer.data;
@@ -353,8 +362,12 @@ afs_dir_MakeDir(dir_file_t dir, afs_int32 * me, afs_int32 * parent)
     for (i = 0; i < NHASHENT; i++)
        dhp->hashTable[i] = 0;
     DRelease(&buffer, 1);
-    afs_dir_Create(dir, ".", me);
-    afs_dir_Create(dir, "..", parent); /* Virtue is its own .. */
+    code = afs_dir_Create(dir, ".", me);
+    if (code)
+       return code;
+    code = afs_dir_Create(dir, "..", parent);
+    if (code)
+       return code;
     return 0;
 }
 
@@ -366,9 +379,12 @@ afs_dir_Lookup(dir_file_t dir, char *entry, void *voidfid)
     afs_int32 *fid = (afs_int32 *) voidfid;
     struct DirBuffer firstbuf, prevbuf;
     struct DirEntry *firstitem;
+    int code;
 
-    if (FindItem(dir, entry, &prevbuf, &firstbuf) != 0)
-       return ENOENT;
+    code = FindItem(dir, entry, &prevbuf, &firstbuf);
+    if (code) {
+        return code;
+    }
     DRelease(&prevbuf, 0);
     firstitem = (struct DirEntry *)firstbuf.data;
 
@@ -387,9 +403,12 @@ afs_dir_LookupOffset(dir_file_t dir, char *entry, void *voidfid,
     afs_int32 *fid = (afs_int32 *) voidfid;
     struct DirBuffer firstbuf, prevbuf;
     struct DirEntry *firstitem;
+    int code;
 
-    if (FindItem(dir, entry, &prevbuf, &firstbuf) != 0)
-       return ENOENT;
+    code = FindItem(dir, entry, &prevbuf, &firstbuf);
+    if (code) {
+        return code;
+    }
     DRelease(&prevbuf, 0);
     firstitem = (struct DirEntry *)firstbuf.data;
 
@@ -497,11 +516,14 @@ afs_dir_IsEmpty(dir_file_t dir)
 /* Return a pointer to an entry, given its number. Also return the maximum
  * size of the entry, which is determined by its position within the directory
  * page.
+ *
+ * If physerr is supplied by caller, it will be set to:
+ *      0       for logical errors
+ *      errno   for physical errors
  */
-
 static int
 GetBlobWithLimit(dir_file_t dir, afs_int32 blobno,
-                struct DirBuffer *buffer, afs_size_t *maxlen)
+               struct DirBuffer *buffer, afs_size_t *maxlen, int *physerr)
 {
     afs_size_t pos;
     int code;
@@ -509,7 +531,7 @@ GetBlobWithLimit(dir_file_t dir, afs_int32 blobno,
     *maxlen = 0;
     memset(buffer, 0, sizeof(struct DirBuffer));
 
-    code = DRead(dir, blobno >> LEPP, buffer);
+    code = DReadWithErrno(dir, blobno >> LEPP, buffer, physerr);
     if (code)
        return code;
 
@@ -522,12 +544,26 @@ GetBlobWithLimit(dir_file_t dir, afs_int32 blobno,
     return 0;
 }
 
+/*
+ * Given an entry's number, return a pointer to that entry.
+ * If physerr is supplied by caller, it will be set to:
+ *      0       for logical errors
+ *      errno   for physical errors
+ */
+int
+afs_dir_GetBlobWithErrno(dir_file_t dir, afs_int32 blobno, struct DirBuffer *buffer,
+                       int *physerr)
+{
+    afs_size_t maxlen = 0;
+    return GetBlobWithLimit(dir, blobno, buffer, &maxlen, physerr);
+}
+
 /* Given an entries number, return a pointer to that entry */
 int
 afs_dir_GetBlob(dir_file_t dir, afs_int32 blobno, struct DirBuffer *buffer)
 {
     afs_size_t maxlen = 0;
-    return GetBlobWithLimit(dir, blobno, buffer, &maxlen);
+    return GetBlobWithLimit(dir, blobno, buffer, &maxlen, NULL);
 }
 
 /* Return an entry, having verified that the name held within the entry
@@ -545,7 +581,7 @@ afs_dir_GetVerifiedBlob(dir_file_t file, afs_int32 blobno,
     int code;
     char *cp;
 
-    code = GetBlobWithLimit(file, blobno, &buffer, &maxlen);
+    code = GetBlobWithLimit(file, blobno, &buffer, &maxlen, NULL);
     if (code)
        return code;
 
@@ -612,16 +648,15 @@ FindItem(dir_file_t dir, char *ename, struct DirBuffer *prevbuf,
     i = afs_dir_DirHash(ename);
     if (dhp->hashTable[i] == 0) {
        /* no such entry */
-       DRelease(&prev, 0);
-       return ENOENT;
+       code = ENOENT;
+       goto out;
     }
 
     code = afs_dir_GetVerifiedBlob(dir,
                                   (u_short) ntohs(dhp->hashTable[i]),
                                   &curr);
     if (code) {
-       DRelease(&prev, 0);
-       return code;
+       goto out;
     }
 
     prev.data = &(dhp->hashTable[i]);
@@ -644,8 +679,11 @@ FindItem(dir_file_t dir, char *ename, struct DirBuffer *prevbuf,
        prev = curr;
        prev.data = &(tp->next);
 
-       if (tp->next == 0)
-           goto out; /* The end of the line */
+       if (tp->next == 0) {
+           /* The end of the line */
+           code = ENOENT;
+           goto out;
+       }
 
        code = afs_dir_GetVerifiedBlob(dir, (u_short) ntohs(tp->next),
                                       &curr);
@@ -653,9 +691,13 @@ FindItem(dir_file_t dir, char *ename, struct DirBuffer *prevbuf,
            goto out;
     }
 
+    /* If we've reached here, we've hit our loop limit. Something is weird with
+     * the directory; maybe a circular hash chain? */
+    code = EIO;
+
 out:
     DRelease(&prev, 0);
-    return ENOENT;
+    return code;
 }
 
 static int
@@ -730,8 +772,10 @@ afs_dir_InverseLookup(void *dir, afs_uint32 vnode, afs_uint32 unique,
     struct DirEntry *entry;
     int code = 0;
 
-    if (FindFid(dir, vnode, unique, &entrybuf) != 0)
-       return ENOENT;
+    code = FindFid(dir, vnode, unique, &entrybuf);
+    if (code) {
+        return code;
+    }
     entry = (struct DirEntry *)entrybuf.data;
 
     if (strlen(entry->name) >= length)
@@ -759,10 +803,13 @@ afs_dir_ChangeFid(dir_file_t dir, char *entry, afs_uint32 *old_fid,
     struct DirEntry *firstitem;
     struct MKFid *fid_old = (struct MKFid *) old_fid;
     struct MKFid *fid_new = (struct MKFid *) new_fid;
+    int code;
 
     /* Find entry. */
-    if (FindItem(dir, entry, &prevbuf, &entrybuf) != 0)
-       return ENOENT;
+    code = FindItem(dir, entry, &prevbuf, &entrybuf);
+    if (code) {
+        return code;
+    }
     firstitem = (struct DirEntry *)entrybuf.data;
     DRelease(&prevbuf, 1);