#include "utils.h" #include "xmalloc.h" #include #include #include #include #include #include #include extern char *program_name; static int copy_file(const char *src, const char *dst) { int src_fd, dst_fd; struct stat st; int save; src_fd = open(src, O_RDONLY); if (src_fd == -1) return -1; fstat(src_fd, &st); dst_fd = creat(dst, st.st_mode); if (dst_fd == -1) { save = errno; close(src_fd); errno = save; return -1; } do { char buffer[8192]; int rcount, wcount; char *ptr; rcount = read(src_fd, buffer, sizeof(buffer)); if (rcount == -1) goto err_exit; if (rcount == 0) { close(dst_fd); close(src_fd); return 0; } ptr = buffer; do { wcount = write(dst_fd, ptr, rcount); if (wcount == -1) goto err_exit; rcount -= wcount; ptr += wcount; } while (rcount > 0); } while (1); err_exit: save = errno; unlink(dst); close(dst_fd); close(src_fd); errno = save; return -1; } int move_file(const char *src, const char *dst) { int rc; rc = rename(src, dst); if (rc == -1) { if (errno != EXDEV) { return -1; } if (copy_file(src, dst) == -1) return -1; if (unlink(src) == -1) { int save; /* grrr... have to remove file we just copied */ save = errno; if (unlink(dst) == -1) { } errno = save; return -1; } } return 0; } int mkpath(const char *filename) { char cwd[1024]; char *str, *s, *e; int rc = 0; if (getcwd(cwd, sizeof(cwd)) == NULL) { /* fatal error */ return -1; } str = xstrdup(filename); s = str; if (*s == '/') { if (chdir("/") == -1) { rc = -1; goto out; } s++; } while ((e = strchr(s, '/')) != NULL) { struct stat st; *e = 0; e++; if (stat(s, &st) == -1) { if (errno != ENOENT) { /* permission denied */ rc = -1; break; } /* file does not exist */ if (mkdir(s, 0777) == -1) { rc = -1; break; } } if (chdir(s) == -1) { rc = -1; break; } s = e; } out: if (chdir(cwd) == -1) { /* fatal error */ rc = -1; } free(str); return rc; } static void strip_slashes(char *filename) { int s, d, slash; s = -1; d = 0; slash = 0; do { s++; if (filename[s] == '/') { if (!slash) { slash = 1; filename[d++] = filename[s]; } } else { slash = 0; filename[d++] = filename[s]; } } while (filename[s]); } int rename_file(const char *filename, const char *destination) { char *new_filename; struct stat st; int rc; new_filename = xstrdup(destination); strip_slashes(new_filename); rc = stat(filename, &st); if (rc == -1) { if (errno != ENOENT) { fprintf(stderr, "%s: error: can't stat() `%s': %s\n", program_name, new_filename, strerror(errno)); free(new_filename); return -1; } } else if (rc) { fprintf(stderr, "%s: file `%s' already exists\n", program_name, new_filename); free(new_filename); return -1; } if (mkpath(new_filename)) { fprintf(stderr, "%s: can't create directory componets for `%s': %s\n", program_name, new_filename, strerror(errno)); free(new_filename); return -1; } if (move_file(filename, new_filename) == -1) { fprintf(stderr, "%s: can't rename file `%s' to `%s': %s\n", program_name, filename, new_filename, strerror(errno)); free(new_filename); return -1; } return 0; }