atomic file uploads. only replace file if content was changed. fixes #220