<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def scan_file(fullpath, relpath, assign_id):
 """ Scan a file for the index fullpath -- The full path to the file relpath -- The path to the file, relative to its base directory assign_id -- Whether to assign an ID to the file if not yet assigned This calls into various modules' scanner functions; the expectation is that the scan_file function will return a truthy value if it was scanned successfully, False if it failed, and None if there is nothing to scan. """


    logger.debug("Scanning file: %s (%s) %s", fullpath, relpath, assign_id)

    def do_scan():
        """ helper function to do the scan and gather the result """
        _, ext = os.path.splitext(fullpath)

        try:
            if ext in ENTRY_TYPES:
                logger.info("Scanning entry: %s", fullpath)
                return entry.scan_file(fullpath, relpath, assign_id)

            if ext in CATEGORY_TYPES:
                logger.info("Scanning meta info: %s", fullpath)
                return category.scan_file(fullpath, relpath)

            return None
        except:  # pylint: disable=bare-except
            logger.exception("Got error parsing %s", fullpath)
            return False

    result = do_scan()
    if result is False and not assign_id:
        logger.info("Scheduling fixup for %s", fullpath)
        THREAD_POOL.submit(scan_file, fullpath, relpath, True)
    else:
        logger.debug("%s complete", fullpath)
        if result:
            set_fingerprint(fullpath)
        SCHEDULED_FILES.remove(fullpath)