// Set a timeout on all sockets to make sure that if a test fails it // won't cause the program to hang void SetTimeout (int socket) { var timeout = new Timeval { tv_sec = 0, tv_usec = 500000, }; if (Syscall.setsockopt (socket, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_RCVTIMEO, timeout) < 0 || Syscall.setsockopt (socket, UnixSocketProtocol.SOL_SOCKET, UnixSocketOptionName.SO_SNDTIMEO, timeout) < 0) UnixMarshal.ThrowExceptionForLastError (); }
public static extern int utimes (string filename, ref Timeval tvp);
private static extern int settimeofday (ref Timeval tv, IntPtr ignore);
public static int settimeofday (ref Timeval tv) { return settimeofday (ref tv, IntPtr.Zero); }
public static extern int settimeofday (ref Timeval tv, ref Timezone tz);
public static int gettimeofday (out Timeval tv) { return gettimeofday (out tv, IntPtr.Zero); }
private static extern int gettimeofday (out Timeval tv, IntPtr ignore);
public static extern int gettimeofday (out Timeval tv, out Timezone tz);
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; }