+static int unlink_all(char *dir)
+{
+ char cmd[strlen(dir) + sizeof("rm -rf ")];
+ sprintf(cmd, "rm -rf %s", dir);
+ if (tools_verbose)
+ printf("Running: %s\n", cmd);
+ if (system(cmd) != 0)
+ warn("Could not remove temporary work in %s", dir);
+ return 0;
+}
+
+char *temp_dir(const void *ctx)
+{
+ /* For first call, create dir. */
+ while (!tmpdir) {
+ tmpdir = getenv("TMPDIR");
+ if (!tmpdir)
+ tmpdir = "/tmp";
+ tmpdir = talloc_asprintf(talloc_autofree_context(),
+ "%s/ccanlint-%u.%lu",
+ tmpdir, getpid(), random());
+ if (mkdir(tmpdir, 0700) != 0) {
+ if (errno == EEXIST) {
+ talloc_free(tmpdir);
+ tmpdir = NULL;
+ continue;
+ }
+ err(1, "mkdir %s failed", tmpdir);
+ }
+ talloc_set_destructor(tmpdir, unlink_all);
+ if (tools_verbose)
+ printf("Created temporary directory %s\n", tmpdir);
+ }
+ return tmpdir;
+}
+
+char *maybe_temp_file(const void *ctx, const char *extension, bool keep,
+ const char *srcname)
+{
+ unsigned baselen;
+ char *f, *suffix = talloc_strdup(ctx, "");
+ struct stat st;
+ unsigned int count = 0;
+
+ if (!keep)
+ srcname = talloc_basename(ctx, srcname);
+ else
+ assert(srcname[0] == '/');
+
+ if (strrchr(srcname, '.'))
+ baselen = strrchr(srcname, '.') - srcname;
+ else
+ baselen = strlen(srcname);
+
+ do {
+ f = talloc_asprintf(ctx, "%s/%.*s%s%s",
+ keep ? "" : temp_dir(ctx),
+ baselen, srcname,
+ suffix, extension);
+ talloc_free(suffix);
+ suffix = talloc_asprintf(ctx, "-%u", ++count);
+ } while (lstat(f, &st) == 0);
+
+ if (tools_verbose)
+ printf("Creating file %s\n", f);
+
+ talloc_free(suffix);
+ return f;
+}
+
+bool move_file(const char *oldname, const char *newname)
+{
+ char *contents;
+ size_t size;
+ int fd;
+ bool ret;
+
+ if (tools_verbose)
+ printf("Moving file %s to %s: ", oldname, newname);
+
+ /* Simple case: rename works. */
+ if (rename(oldname, newname) == 0) {
+ if (tools_verbose)
+ printf("rename worked\n");
+ return true;
+ }
+
+ /* Try copy and delete: not atomic! */
+ contents = grab_file(NULL, oldname, &size);
+ if (!contents) {
+ if (tools_verbose)
+ printf("read failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ fd = open(newname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ if (fd < 0) {
+ if (tools_verbose)
+ printf("output open failed: %s\n", strerror(errno));
+ ret = false;
+ goto free;
+ }
+
+ ret = write_all(fd, contents, size);
+ if (close(fd) != 0)
+ ret = false;
+
+ if (ret) {
+ if (tools_verbose)
+ printf("copy worked\n");
+ unlink(oldname);
+ } else {
+ if (tools_verbose)
+ printf("write/close failed\n");
+ unlink(newname);
+ }