cfilefseeklibmagic

fseek fails on open file pointer


I'm having trouble with fseek. I have a file pointer that contains fetched HTTP data. I then let libmagic determine the mime type of the file and want to rewind afterwards:

char *mime_type (int fd)
{
    char *mime;
    magic_t magic;

    magic = magic_open(MAGIC_MIME_TYPE);
    magic_load(magic, MAGIC_FILE_NAME);
    mime = (char*)magic_descriptor(magic, fd);

    magic_close(magic);
    return (mime);
}

int fetch_pull() {
    fetch_state = fopen("/tmp/curl_0", "r");
    if (fetch_state == NULL) {
      perror("fetch_pull(): Could not open file handle");
      return (1);
    }
    fd = fileno(fetch_state);
    mime = mime_type(fd);
    if (fseek(fetch_state, 0L, SEEK_SET) != 0) {
      perror("fetch_pull(): Could not rewind file handle");
      return (1);
    }
    if (mime != NULL && strstr(mime, "text/") != NULL) {
      /* do things */
    } else if (mime != NULL && strstr(mime, "image/") != NULL) {
      /* do other things */
    }
    return (0);
}

This throws "fetch_pull(): Could not rewind file handle: Bad file descriptor". What is wrong?


Solution

  • /tmp/curl_0 is a pipe, isn't it? You cannot rewind a pipe. What's read is gone.

    And you cannot combine FILE operations and file descriptor operations, since FILEs have an additional buffer, they read ahead.

    If /tmp/curl_0 is a regular file, then open a file descriptor with open(const char *path, int oflag, ...). After invoking mime_type(fd), you can first rewind the stream, then wrap the file descriptor into FILE handle with fdopen(int fildes, const char *mode). Or just close the file descriptor and use the regular fopen() afterwards:

    int fd = open("/tmp/curl_0", O_RDONLY);
    if (fd == -1) {
        perror("Could not open file");
        return -1;
    }
    char *mime = mime_type(fd);
    
        /***** EITHER: */
    
    close(fd);
    FILE *file = fopen("/tmp/curl_0", "r");
    
        /***** OR (the worse option!) */
    
    if (lseek(fd, 0, SEEK_SET) == -1) {
        perror("Could not seek");
        return -1;
    }
    FILE *fdopen = fopen(fd, "r");
    
        /***********/
    
    if (!file) {
        perror("Could not open file");
        return -1;
    }
    /* do things */
    fclose(file);