#ifdef KERNEL
# if !defined(UKERNEL)
# include "h/types.h"
-# include "h/param.h"
+# if !defined(AFS_LINUX26_ENV)
+# include "h/param.h"
+# endif
# ifdef AFS_AUX_ENV
# include "h/mmu.h"
# include "h/seg.h"
# 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
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;
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;
DRelease(&prevbuf, 1);
index = DVOffset(&entrybuf) / 32;
nitems = afs_dir_NameBlobs(firstitem->name);
- DRelease(&entrybuf, 0);
+ /* Clear entire DirEntry and any DirXEntry extensions */
+ memset(firstitem, 0, nitems * sizeof(*firstitem));
+ DRelease(&entrybuf, 1);
FreeBlobs(dir, index, nitems);
return 0;
}
/* read the page in. */
if (DRead(dir, i, &pagebuf) != 0) {
- DRelease(&headerbuf, 1);
break;
}
pp = (struct PageHeader *)pagebuf.data;
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;
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;
struct DirHeader *dhp;
struct DirEntry *ep;
int code = 0;
+ int elements;
if (DRead(dir, 0, &headerbuf) != 0)
return EIO;
for (i = 0; i < NHASHENT; i++) {
/* For each hash chain, enumerate everyone on the list. */
num = ntohs(dhp->hashTable[i]);
- while (num != 0) {
+ elements = 0;
+ while (num != 0 && elements < BIGMAXPAGES * EPP) {
+ elements++;
+
/* Walk down the hash table list. */
- DErrno = 0;
- if (afs_dir_GetBlob(dir, num, &entrybuf) != 0) {
- if (DErrno) {
- /* we failed, return why */
- DRelease(&headerbuf, 0);
- return DErrno;
- }
+ code = afs_dir_GetVerifiedBlob(dir, num, &entrybuf);
+ if (code)
+ goto out;
+
+ ep = (struct DirEntry *)entrybuf.data;
+ if (!ep) {
+ DRelease(&entrybuf, 0);
break;
}
- ep = (struct DirEntry *)entrybuf.data;
num = ntohs(ep->next);
code = (*proc) (hook, ep->name, ntohl(ep->fid.vnode),
ntohl(ep->fid.vunique));
DRelease(&entrybuf, 0);
if (code)
- break;
+ goto out;
}
}
+
+out:
DRelease(&headerbuf, 0);
return 0;
}
struct DirBuffer headerbuf, entrybuf;
struct DirHeader *dhp;
struct DirEntry *ep;
+ int elements;
if (DRead(dir, 0, &headerbuf) != 0)
return 0;
for (i = 0; i < NHASHENT; i++) {
/* For each hash chain, enumerate everyone on the list. */
num = ntohs(dhp->hashTable[i]);
- while (num != 0) {
+ elements = 0;
+ while (num != 0 && elements < BIGMAXPAGES * EPP) {
+ elements++;
/* Walk down the hash table list. */
- if (afs_dir_GetBlob(dir, num, &entrybuf) != 0);
+ if (afs_dir_GetVerifiedBlob(dir, num, &entrybuf) != 0)
break;
ep = (struct DirEntry *)entrybuf.data;
if (strcmp(ep->name, "..") && strcmp(ep->name, ".")) {
return 0;
}
-int
-afs_dir_GetBlob(dir_file_t dir, afs_int32 blobno, struct DirBuffer *buffer)
+/* 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.
+ */
+
+static int
+GetBlobWithLimit(dir_file_t dir, afs_int32 blobno,
+ struct DirBuffer *buffer, afs_size_t *maxlen)
{
+ afs_size_t pos;
int code;
+ *maxlen = 0;
memset(buffer, 0, sizeof(struct DirBuffer));
code = DRead(dir, blobno >> LEPP, buffer);
if (code)
return code;
- buffer->data = (void *)(((long)buffer->data) + 32 * (blobno & (EPP - 1)));
+ pos = 32 * (blobno & (EPP - 1));
+
+ *maxlen = AFS_PAGESIZE - pos - 1;
+
+ buffer->data = (void *)(((char *)buffer->data) + pos);
return 0;
}
+/* 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 an entry, having verified that the name held within the entry
+ * doesn't overflow off the end of the directory page it is contained
+ * within
+ */
+
+int
+afs_dir_GetVerifiedBlob(dir_file_t file, afs_int32 blobno,
+ struct DirBuffer *outbuf)
+{
+ struct DirEntry *dir;
+ struct DirBuffer buffer;
+ afs_size_t maxlen;
+ int code;
+ char *cp;
+
+ code = GetBlobWithLimit(file, blobno, &buffer, &maxlen);
+ if (code)
+ return code;
+
+ dir = (struct DirEntry *)buffer.data;
+
+ /* A blob is only valid if the name within it is NULL terminated before
+ * the end of the blob's containing page */
+ for (cp = dir->name; *cp != '\0' && cp < ((char *)dir) + maxlen; cp++);
+
+ if (*cp != '\0') {
+ DRelease(&buffer, 0);
+ return EIO;
+ }
+
+ *outbuf = buffer;
+ return 0;
+}
+
int
afs_dir_DirHash(char *string)
{
tval = hval & (NHASHENT - 1);
if (tval == 0)
return tval;
- else if (hval >= 1<<31)
+ else if (hval >= 1u<<31)
tval = NHASHENT - tval;
return tval;
}
struct DirBuffer curr, prev;
struct DirHeader *dhp;
struct DirEntry *tp;
+ int elements;
memset(prevbuf, 0, sizeof(struct DirBuffer));
memset(itembuf, 0, sizeof(struct DirBuffer));
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_GetBlob(dir, (u_short) ntohs(dhp->hashTable[i]),
- &curr);
+ 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]);
+ elements = 0;
+ /* Detect circular hash chains. Absolute max size of a directory */
+ while (elements < BIGMAXPAGES * EPP) {
+ elements++;
- while (1) {
/* Look at each entry on the hash chain */
tp = (struct DirEntry *)curr.data;
if (!strcmp(ename, tp->name)) {
*itembuf = curr;
return 0;
}
+
DRelease(&prev, 0);
- if (tp->next == 0) {
- /* The end of the line */
- DRelease(&curr, 0);
- return ENOENT;
- }
prev = curr;
prev.data = &(tp->next);
- code = afs_dir_GetBlob(dir, (u_short) ntohs(tp->next), &curr);
- if (code) {
- DRelease(&prev, 0);
- return code;
+ if (tp->next == 0) {
+ /* The end of the line */
+ code = ENOENT;
+ goto out;
}
+
+ code = afs_dir_GetVerifiedBlob(dir, (u_short) ntohs(tp->next),
+ &curr);
+ if (code)
+ goto out;
}
- /* Never reached */
+
+ /* 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 code;
}
static int
struct DirBuffer curr, header;
struct DirHeader *dhp;
struct DirEntry *tp;
+ int elements;
memset(itembuf, 0, sizeof(struct DirBuffer));
for (i=0; i<NHASHENT; i++) {
if (dhp->hashTable[i] != 0) {
- code = afs_dir_GetBlob(dir, (u_short)ntohs(dhp->hashTable[i]),
- &curr);
+ code = afs_dir_GetVerifiedBlob(dir,
+ (u_short)ntohs(dhp->hashTable[i]),
+ &curr);
if (code) {
DRelease(&header, 0);
return code;
}
-
- while (curr.data != NULL) {
+ elements = 0;
+ while(curr.data != NULL && elements < BIGMAXPAGES * EPP) {
+ elements++;
tp = (struct DirEntry *)curr.data;
if (vnode == ntohl(tp->fid.vnode)
if (next == 0)
break;
- code = afs_dir_GetBlob(dir, (u_short)ntohs(next), &curr);
+ code = afs_dir_GetVerifiedBlob(dir, (u_short)ntohs(next),
+ &curr);
if (code) {
DRelease(&header, 0);
return code;
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)
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);