public TargetExistsAction TargetExists(string file, DateTime sourceTime, long sourceSize, DateTime targetTime, long targetSize, bool multiple) { const int padding = 14; const int minEllipse = 22; const string fmt = "Target file \"{0}\" already exists"; TargetExistsAction result = TargetExistsAction.Cancel; var msg = String.Format(fmt, file); if (msg.Length > Terminal.Cols - padding) { msg = String.Format(fmt, file.Ellipsize(Terminal.Cols - 8 - fmt.Length)); } var d = new Dialog(msg.Length + padding, 13 + (multiple ? 3 : 0), "File exists"); d.ErrorColors(); d.Add(new Label(2, 1, msg)); // TODO: compute what changes actually matter (year, month, day, hour, minute) d.Add(new Label(2, 3, String.Format("Source date: {0}, size {1}", sourceTime, sourceSize))); d.Add(new Label(2, 4, String.Format("Target date: {0}, size {1}", targetTime, targetSize))); d.Add(new Label(2, 6, "Override this target?")); MakeButton(d, 24, 6, "Yes", () => result = TargetExistsAction.Overwrite); MakeButton(d, 32, 6, "No", () => result = TargetExistsAction.Skip); MakeButton(d, 39, 6, "Append", () => result = TargetExistsAction.Append); if (multiple) { d.Add(new Label(2, 8, "Override all targets?")); MakeButton(d, 24, 8, "aLl", () => result = TargetExistsAction.AlwaysOverwrite); MakeButton(d, 32, 8, "Update", () => result = TargetExistsAction.AlwaysUpdate); MakeButton(d, 43, 8, "None", () => result = TargetExistsAction.AlwaysSkip); MakeButton(d, 24, 9, "if Size differs", () => result = TargetExistsAction.AlwaysUpdateOnSizeMismatch); } MakeButton(d, (d.w - 4 - "Cancel".Length) / 2, 8 + (multiple ? 3 : 0), "Cancel", () => { }); Terminal.Run(d); return(result); }
bool CopyFile(string source_absolute_path, string target_path) { bool ret = false; bool target_exists = false; // Stat target Stat tstat; lock (this) ProcessedFiles++; while (Syscall.stat(target_path, out tstat) == 0) { if (tstat.st_mode.HasFlag(FilePermissions.S_IFDIR)) { if (ShouldRetryOperation("Target file is a directory", "Source file \"{0}\"", Path.GetFileName(source_absolute_path))) { continue; } return(false); } else { target_exists = true; } break; } // Open Source int source_fd; while (true) { source_fd = Syscall.open(source_absolute_path, OpenFlags.O_RDONLY, (FilePermissions)0); if (source_fd != -1) { break; } if (ShouldRetryOperation("While opening \"{0}\"", target_path)) { continue; } return(false); } Stat stat; while (true) { if (Syscall.fstat(source_fd, out stat) != -1) { break; } if (ShouldRetryOperation("While probing for state of \"{0}\"", target_path)) { continue; } goto close_source; } // Make sure we are not overwriting the same file if (stat.st_dev == tstat.st_dev && stat.st_ino == tstat.st_ino) { Interaction.Error("Can not copy a file into itself"); skip = true; goto close_source; } lock (this) { CurrentFileProgress = 0; CurrentFileSize = tstat.st_size; } if (target_exists) { if (target_exists_action < TargetExistsAction.AlwaysOverwrite) { target_exists_action = Interaction.TargetExists( target_path, NativeConvert.ToDateTime(stat.st_mtime), stat.st_size, NativeConvert.ToDateTime(tstat.st_mtime), tstat.st_size, Interaction.Count > 1); } if (target_exists_action == TargetExistsAction.Cancel) { goto close_source; } if (target_exists_action == TargetExistsAction.Skip) { goto close_source; } } // Open target int target_fd; switch (target_exists_action) { case TargetExistsAction.AlwaysUpdate: if (stat.st_mtime > tstat.st_mtime) { goto case TargetExistsAction.Overwrite; } skip = true; goto close_source; case TargetExistsAction.AlwaysUpdateOnSizeMismatch: if (stat.st_size != tstat.st_size) { goto case TargetExistsAction.Overwrite; } skip = true; goto close_source; // Real cancels are taken care of immediately after the dialog // this means: never used, target does not exist. case TargetExistsAction.Cancel: case TargetExistsAction.AlwaysOverwrite: case TargetExistsAction.Overwrite: target_fd = Syscall.open(target_path, OpenFlags.O_CREAT | OpenFlags.O_WRONLY, FilePermissions.S_IWUSR); break; case TargetExistsAction.Append: target_fd = Syscall.open(target_path, OpenFlags.O_APPEND, FilePermissions.S_IWUSR); break; default: throw new Exception(String.Format("Internal error: unhandled TargetExistsAction value {0}", target_exists_action)); } while (true) { if (target_fd != -1) { break; } if (ShouldRetryOperation("While creating \"{0}\"", target_path)) { continue; } goto close_source; } AllocateBuffer(); long n; do { while (true) { n = Syscall.read(source_fd, io_buffer, COPY_BUFFER_SIZE); if (n != -1) { break; } if (ShouldRetryOperation("While reading \"{0}\"", Path.GetFileName(source_absolute_path))) { continue; } goto close_both; } while (true) { long count = Syscall.write(target_fd, io_buffer, (ulong)n); if (count != -1) { break; } if (ShouldRetryOperation("While writing \"{0}\"", target_path)) { continue; } goto close_both; } lock (this) { ProcessedBytes += n; CurrentFileSize += n; } } while (n != 0); // File mode while (true) { n = Syscall.fchmod(target_fd, stat.st_mode); if (n == 0) { break; } if (ShouldRetryOperation("Setting permissions on \"{0}\"", target_path)) { continue; } goto close_both; } // The following are not considered errors if we can not set them ret = true; // preserve owner and group if running as root if (Syscall.geteuid() == 0) { Syscall.fchown(target_fd, stat.st_uid, stat.st_gid); } // Set file time Timeval[] dates = new Timeval [2] { new Timeval() { tv_sec = stat.st_atime }, new Timeval() { tv_sec = stat.st_mtime } }; Syscall.futimes(target_fd, dates); close_both: Syscall.close(target_fd); close_source: Syscall.close(source_fd); return(ret); }
bool CopyFile(string source_absolute_path, string target_path) { bool ret = false; bool target_exists = false; // Stat target Stat tstat; lock (this) ProcessedFiles++; while (Syscall.stat (target_path, out tstat) == 0){ if (tstat.st_mode.HasFlag (FilePermissions.S_IFDIR)){ if (ShouldRetryOperation ("Target file is a directory", "Source file \"{0}\"", Path.GetFileName (source_absolute_path))) continue; return false; } else { target_exists = true; } break; } // Open Source int source_fd; while (true){ source_fd = Syscall.open (source_absolute_path, OpenFlags.O_RDONLY, (FilePermissions) 0); if (source_fd != -1) break; if (ShouldRetryOperation ("While opening \"{0}\"", target_path)) continue; return false; } Stat stat; while (true){ if (Syscall.fstat (source_fd, out stat) != -1) break; if (ShouldRetryOperation ("While probing for state of \"{0}\"", target_path)) continue; goto close_source; } // Make sure we are not overwriting the same file if (stat.st_dev == tstat.st_dev && stat.st_ino == tstat.st_ino){ Interaction.Error ("Can not copy a file into itself"); skip = true; goto close_source; } lock (this){ CurrentFileProgress = 0; CurrentFileSize = tstat.st_size; } if (target_exists){ if (target_exists_action < TargetExistsAction.AlwaysOverwrite){ target_exists_action = Interaction.TargetExists ( target_path, NativeConvert.ToDateTime (stat.st_mtime), stat.st_size, NativeConvert.ToDateTime (tstat.st_mtime), tstat.st_size, Interaction.Count > 1); } if (target_exists_action == TargetExistsAction.Cancel) goto close_source; if (target_exists_action == TargetExistsAction.Skip) goto close_source; } // Open target int target_fd; switch (target_exists_action){ case TargetExistsAction.AlwaysUpdate: if (stat.st_mtime > tstat.st_mtime) goto case TargetExistsAction.Overwrite; skip = true; goto close_source; case TargetExistsAction.AlwaysUpdateOnSizeMismatch: if (stat.st_size != tstat.st_size) goto case TargetExistsAction.Overwrite; skip = true; goto close_source; // Real cancels are taken care of immediately after the dialog // this means: never used, target does not exist. case TargetExistsAction.Cancel: case TargetExistsAction.AlwaysOverwrite: case TargetExistsAction.Overwrite: target_fd = Syscall.open (target_path, OpenFlags.O_CREAT | OpenFlags.O_WRONLY, FilePermissions.S_IWUSR); break; case TargetExistsAction.Append: target_fd = Syscall.open (target_path, OpenFlags.O_APPEND, FilePermissions.S_IWUSR); break; default: throw new Exception (String.Format ("Internal error: unhandled TargetExistsAction value {0}", target_exists_action)); } while (true){ if (target_fd != -1) break; if (ShouldRetryOperation ("While creating \"{0}\"", target_path)) continue; goto close_source; } AllocateBuffer (); long n; do { while (true){ n = Syscall.read (source_fd, io_buffer, COPY_BUFFER_SIZE); if (n != -1) break; if (ShouldRetryOperation ("While reading \"{0}\"", Path.GetFileName (source_absolute_path))) continue; goto close_both; } while (true){ long count = Syscall.write (target_fd, io_buffer, (ulong) n); if (count != -1) break; if (ShouldRetryOperation ("While writing \"{0}\"", target_path)) continue; goto close_both; } lock (this){ ProcessedBytes += n; CurrentFileSize += n; } } while (n != 0); // File mode while (true){ n = Syscall.fchmod (target_fd, stat.st_mode); if (n == 0) break; if (ShouldRetryOperation ("Setting permissions on \"{0}\"", target_path)) continue; goto close_both; } // The following are not considered errors if we can not set them ret = true; // preserve owner and group if running as root if (Syscall.geteuid () == 0) Syscall.fchown (target_fd, stat.st_uid, stat.st_gid); // Set file time Timeval [] dates = new Timeval [2] { new Timeval () { tv_sec = stat.st_atime }, new Timeval () { tv_sec = stat.st_mtime } }; Syscall.futimes (target_fd, dates); close_both: Syscall.close (target_fd); close_source: Syscall.close (source_fd); return ret; }