Merge all files in a directory with a specific extension
scandir

It is not a good name for 2 reasons. First, it exists in a global namespace, and second, it doesn't tell what the function does. Your scandir not only scans the directory, but does an actual merge as well. I would recommend to scan the directory with a standard library's scandir and then merge files (from the list it returns) in a merge function.

A perk benefit of using a stock scandir is an ability to control the merge order. Right now it is unpredictable.

Yet another benefit of separating responsibilities is that if outfile is in the same directory with source files and it has an target extension, the results could be very strange.
has_extension presumes that the extension is always 3 characters. It is not necessarily so. It should calculate an actual length of the ext argument.
append_to_file produces a misleading diagnostics. The fopen may fail for many reasons, but file being empty is not one of them. Display the error message with perror or strerror.
path_combine

Contrary to a popular belief, windows understands a forward slash as a path separator (backslash is an artifact of cmd.exe). There's no need to special case windows.

It is also not necessary to test for last character for being a separator. Just add the separator anyway, it is harmless.

That said, I don't think that you need it at all: just chdir() to the source directory first.