NULL-eating / elimination version of fgets() in C I've come up with the following routine to read data from a file stream, but I don't want any NULLs in the stream to terminate the string early.  This function will read in a "line", and allow it to be processed with normal C string functions.  Does anyone see any inherent problems or potential bugs in this routine?

char *my_fgets(char *Buf, int iMaxCount, FILE *fp)
{
    // Handle basic failures.
    if(!Buf) return NULL;
    if(iMaxCount &lt; 1) return NULL;
    if(!fp) return NULL;

    // Create a buffer on the heap for our data to be read in
    char *lbuf = (char*)malloc(iMaxCount);
    char *p = lbuf;

    // Zero out the buffer, no stray chars please.
    memset(Buf, 0x00, iMaxCount);

    // Where are we at in the file?
    int b = ftell(fp);

    // Read in the buffer, up to iMaxCount-1.  Leave one char for a final NULL.
    size_t read = fread((void*)&amp;lbuf[0], sizeof(char), iMaxCount-1, fp);
    lbuf[iMaxCount-1] = NULL;

    // Failed.
    if(!read) {
        free(lbuf);
        return NULL;
    }
    // Walk the buffer, looking for a newline char.  Once we find it, we know we are at the end of the line, 
    // but we don't want to read past the number of bytes we originally read, in case we did not hit a newline.
    size_t left = read;
    while((left) &amp;&amp; *(p++) != '\n') left--;

    // Copy the data we read to the return Buffer, up to the newline char.
    memcpy(Buf, lbuf, p - lbuf);
    // Set the file pointer to the newline char + 1
    fseek(fp, b+(p - lbuf), SEEK_SET);

    // Setup how many bytes we have left in the buffer to look at.
    left = (p - lbuf);
    p = Buf;    

    while(left)
    {
        // Walk the buffer, looking for NULL chars.
        if(*(p++) == NULL) {
            char *p1;
            // We hit a NULL, so shift the buffer left, eat the NULL, and continue our search.
            for(p1 = p-1;p1 &lt; (Buf + (iMaxCount-1));p1++) p1[0] = p1[1];
            // We ate one char, so we need to step back one byte, and continue our search.  This handles a case where two NULLs may be back to back.
            p--;
        }
        left--;
    } 

    // If our last char is not a NULL, we need to set it to NULL to properly terminate the string.
    if((p &gt; Buf) &amp;&amp; *(p-1) != 0x0a &amp;&amp; *p != NULL) *(--p) = 0x00;

    // Free our work buffer, and return the new 'clean' data.
    free(lbuf);
    return Buf;
}


It might of importance to note that this code is called by a Kernel driver, and MUST be fast.  Speed is totally of the essence here, which is why this is all in one function, and uses calls like fread() over fgets() to get a chunk of data in one shot.  That might not matter in the final analysis, but I thought I would mention it.
There's absolutely no need for an intermediate (dynamic) buffer. Everything you do can be done directly in the client buffer (Buf).

I don't see a reason for fread-ing data. fgets works as good, and spares you from calling ftell and fseek.

The way you remove null chars is suboptimal. I'd keep count of null chars encountered, and shift non-null chars by that count, in a single loop. In any case, I'd factor removal code into a separate function (No Raw Loops rule strikes again).

Looking for a newline is better be done with a standard memchr().

That said, the main code condenses to

char * fgets_and_remove_nulls(char * buf, size_t count, FILE * fp)
{
    memset(buf, 0, size);
    if(fgets(buf, size, fp) == NULL) return NULL;
    char * end = memchr(buf, '\n', size);
    if (end == NULL) end = buf + size;
    remove_null_chars(buf, end);
    return buf;
}