📄 file.c
字号:
if (return_status != FILE_CONT)
return return_status;
}
}
if (!do_append) {
/* .ado: OS2 and NT don't have hardlinks */
#ifndef OS2_NT
/* Check the hardlinks */
if (!op_follow_links && sb.st_nlink > 1 &&
check_hardlinks (src_path, dst_path, &sb) == 1) {
/* We have made a hardlink - no more processing is necessary */
return return_status;
}
if (S_ISLNK (sb.st_mode))
return make_symlink (src_path, dst_path);
#endif /* !OS_NT */
if (S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode) || S_ISFIFO (sb.st_mode)
|| S_ISSOCK (sb.st_mode)){
retry_mknod:
if (mc_mknod (dst_path, sb.st_mode & umask_kill, sb.st_rdev) < 0){
return_status = file_error
(_(" Cannot create special file \"%s\" \n %s "), dst_path);
if (return_status == FILE_RETRY)
goto retry_mknod;
return return_status;
}
/* Success */
#ifndef OS2_NT
retry_mknod_uidgid:
if (preserve_uidgid && mc_chown (dst_path, sb.st_uid, sb.st_gid)){
temp_status = file_error
(_(" Cannot chown target file \"%s\" \n %s "), dst_path);
if (temp_status == FILE_RETRY)
goto retry_mknod_uidgid;
return temp_status;
}
#endif
#ifndef __os2__
retry_mknod_chmod:
if (preserve && mc_chmod (dst_path, sb.st_mode & umask_kill) < 0){
temp_status = file_error (_(" Cannnot chmod target file \"%s\" \n %s "), dst_path);
if (temp_status == FILE_RETRY)
goto retry_mknod_chmod;
return temp_status;
}
#endif
return FILE_CONT;
}
}
if (!do_append && !vfs_file_is_local (src_path) && vfs_file_is_local (dst_path)){
mc_setctl (src_path, MCCTL_SETREMOTECOPY, dst_path);
}
retry_src_open:
if ((source_desc = mc_open (src_path, O_RDONLY)) < 0){
return_status = file_error
(_(" Cannot open source file \"%s\" \n %s "), src_path);
if (return_status == FILE_RETRY)
goto retry_src_open;
do_append = 0;
return return_status;
}
resources |= 1;
do_remote_copy = mc_ctl (source_desc, MCCTL_ISREMOTECOPY, 0);
if (!do_remote_copy) {
retry_src_fstat:
if (mc_fstat (source_desc, &sb)){
return_status = file_error
(_(" Cannot fstat source file \"%s\" \n %s "), src_path);
if (return_status == FILE_RETRY)
goto retry_src_fstat;
do_append = 0;
goto ret;
}
#if 0
/* Im not sure if we can delete this. sb is already filled by
(*xstat)() - Norbert. */
} else {
retry_src_rstat:
if (mc_stat (src_path, &sb)){
return_status = file_error
(_(" Cannot stat source file \"%s\" \n %s "), src_path);
if (return_status == FILE_RETRY)
goto retry_src_rstat;
do_append = 0;
goto ret;
}
#endif
}
src_mode = sb.st_mode;
#ifndef OS2_NT
src_uid = sb.st_uid;
src_gid = sb.st_gid;
#endif
utb.actime = sb.st_atime;
utb.modtime = sb.st_mtime;
file_size = sb.st_size;
/* Create the new regular file with small permissions initially,
do not create a security hole. */
if (!do_remote_copy) {
retry_dst_open:
if ((do_append &&
(dest_desc = mc_open (dst_path, O_WRONLY | O_APPEND)) < 0) ||
(!do_append &&
(dest_desc = mc_open (dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)) {
return_status = file_error
(_(" Cannot create target file \"%s\" \n %s "), dst_path);
if (return_status == FILE_RETRY)
goto retry_dst_open;
do_append = 0;
goto ret;
}
resources |= 2; /* dst_path exists/dst_path opened */
resources |= 4; /* remove short file */
}
appending = do_append;
do_append = 0;
if (!do_remote_copy) {
retry_dst_fstat:
/* Find out the optimal buffer size. */
if (mc_fstat (dest_desc, &sb)){
return_status = file_error
(_(" Cannot fstat target file \"%s\" \n %s "), dst_path);
if (return_status == FILE_RETRY)
goto retry_dst_fstat;
goto ret;
}
buf_size = 8*1024;
buf = (char *) xmalloc (buf_size, "copy_file_file");
}
return_status = show_file_progress (0, file_size);
mc_refresh ();
if (return_status != FILE_CONT)
goto ret;
if (!do_remote_copy){
for (;;){
retry_src_read:
n_read = mc_read (source_desc, buf, buf_size);
if (n_read < 0){
return_status = file_error
(_(" Cannot read source file \"%s\" \n %s "), src_path);
if (return_status == FILE_RETRY)
goto retry_src_read;
goto ret;
}
if (n_read == 0)
break;
n_read_total += n_read;
retry_dst_write:
n_written = mc_write (dest_desc, buf, n_read);
if (n_written < n_read){
return_status = file_error
(_(" Cannot write target file \"%s\" \n %s "), dst_path);
if (return_status == FILE_RETRY)
goto retry_dst_write;
goto ret;
}
return_status = show_file_progress (n_read_total, file_size);
mc_refresh ();
if (return_status != FILE_CONT)
goto ret;
}
} else {
struct timeval tv_current;
struct timeval tv_transfer_start;
struct timeval tv_last_update;
struct timeval tv_last_input;
int i, size, secs, update_secs;
long dt;
char *stalled_msg;
gettimeofday (&tv_transfer_start, (struct timezone *) NULL);
tv_last_update = tv_transfer_start;
eta_secs = 0.0;
for (i = 1; i;) {
switch (size = mc_ctl (source_desc, MCCTL_REMOTECOPYCHUNK, 8192)) {
case MCERR_TARGETOPEN:
message_1s (1, MSG_ERROR, _(" Can't open target file "));
goto ret;
case MCERR_READ:
goto ret;
case MCERR_WRITE:
message_1s (1, MSG_ERROR, _(" Can't write to local target file "));
goto ret;
case MCERR_DATA_ON_STDIN:
break;
case MCERR_FINISH:
resources |= 8;
i = 0;
break;
}
/* the first time we reach this line the target file has been created
or truncated and we actually have a short target file.
Do we really want to delete the target file when the ftp transfer
fails? If we don't delete it we would be able to use reget later.
(Norbert) */
resources |= 4; /* remove short file */
if (i && size != MCERR_DATA_ON_STDIN){
n_read_total += size;
/* Windows NT ftp servers report that files have no
* permissions: -------, so if we happen to have actually
* read something, we should fix the permissions.
*/
if (!(src_mode &
((S_IRUSR|S_IWUSR|S_IXUSR) /* user */
|(S_IXOTH|S_IWOTH|S_IROTH) /* other */
|(S_IXGRP|S_IWGRP|S_IRGRP)))) /* group */
src_mode = S_IRUSR|S_IWUSR|S_IROTH|S_IRGRP;
gettimeofday (&tv_last_input, NULL);
}
/* Timed operations: */
gettimeofday (&tv_current, NULL);
/* 1. Update rotating dash after some time (hardcoded to 2 seconds) */
secs = (tv_current.tv_sec - tv_last_update.tv_sec);
if (secs > 2){
rotate_dash ();
tv_last_update = tv_current;
}
/* 2. Check for a stalled condition */
update_secs = (tv_current.tv_sec - tv_last_input.tv_sec);
stalled_msg = "";
if (update_secs > 4){
stalled_msg = _("(stalled)");
}
/* 3. Compute ETA */
if (secs > 2 || eta_secs == 0.0){
dt = (tv_current.tv_sec - tv_transfer_start.tv_sec);
if (n_read_total){
eta_secs = ((dt / (double) n_read_total) * file_size) - dt;
bps = n_read_total / ((dt < 1) ? 1 : dt);
} else
eta_secs = 0.0;
}
/* 4. Compute BPS rate */
if (secs > 2){
bps_time = (tv_current.tv_sec - tv_transfer_start.tv_sec);
if (bps_time < 1)
bps_time = 1;
bps = n_read_total / bps_time;
}
label_set_text (stalled_label, stalled_msg);
return_status = show_file_progress (n_read_total, file_size);
mc_refresh ();
if (return_status != FILE_CONT)
goto ret;
}
}
resources &= ~4; /* copy successful, don't remove target file */
ret:
if (buf)
free (buf);
retry_src_close:
if ((resources & 1) && mc_close (source_desc) < 0){
temp_status = file_error
(_(" Cannot close source file \"%s\" \n %s "), src_path);
if (temp_status == FILE_RETRY)
goto retry_src_close;
if (temp_status == FILE_ABORT)
return_status = temp_status;
}
retry_dst_close:
if ((resources & 2) && mc_close (dest_desc) < 0){
temp_status = file_error
(_(" Cannot close target file \"%s\" \n %s "), dst_path);
if (temp_status == FILE_RETRY)
goto retry_dst_close;
return_status = temp_status;
}
if (resources & 4) {
/* Remove short file */
mc_unlink (dst_path);
if (do_remote_copy) {
mc_ctl (source_desc, MCCTL_FINISHREMOTE, -1);
}
} else if (resources & (2|8)) {
/* no short file and destination file exists */
#ifndef OS2_NT
if (!appending && preserve_uidgid) {
retry_dst_chown:
if (mc_chown (dst_path, src_uid, src_gid)){
temp_status = file_error
(_(" Cannot chown target file \"%s\" \n %s "), dst_path);
if (temp_status == FILE_RETRY)
goto retry_dst_chown;
return_status = temp_status;
}
}
#endif
/* .ado: according to the XPG4 standard, the file must be closed before
* chmod can be invoked
*/
retry_dst_chmod:
if (!appending && mc_chmod (dst_path, src_mode & umask_kill)){
temp_status = file_error
(_(" Cannot chmod target file \"%s\" \n %s "), dst_path);
if (temp_status == FILE_RETRY)
goto retry_dst_chmod;
return_status = temp_status;
}
if (!appending && preserve)
mc_utime (dst_path, &utb);
}
return return_status;
}
/*
* I think these copy_*_* functions should have a return type.
* anyway, this function *must* have two directories as arguments.
*/
/* FIXME: This function needs to check the return values of the
function calls */
int
copy_dir_dir (char *s, char *d, int toplevel, int move_over, int delete,
struct link *parent_dirs)
{
#ifdef __os2__
DIR *next;
#else
struct dirent *next;
#endif
struct stat buf, cbuf;
DIR *reading;
char *path, *mdpath, *dest_file, *dest_dir;
int return_status = FILE_CONT;
struct utimbuf utb;
struct link *lp;
/* First get the mode of the source dir */
retry_src_stat:
if ((*xstat) (s, &cbuf)){
return_status = file_error (_(" Cannot stat source directory \"%s\" \n %s "), s);
if (return_status == FILE_RETRY)
goto retry_src_stat;
return return_status;
}
if (is_in_linklist (dest_dirs, s, &cbuf)) {
/* Don't copy a directory we created before (we don't want to copy
infinitely if a directory is copied into itself) */
/* FIXME: should there be an error message and FILE_SKIP? - Norbert */
return FILE_CONT;
}
/* Hmm, hardlink to directory??? - Norbert */
/* FIXME: In this step we should do something
in case the destination already exist */
/* Check the hardlinks */
if (preserve && cbuf.st_nlink > 1 && check_hardlinks (s, d, &cbuf) == 1) {
/* We have made a hardlink - no more processing is necessary */
return return_status;
}
if (!S_ISDIR (cbuf.st_mode)){
return_status = file_error (_(" Source directory \"%s\" is not a directory \n %s "), s);
if (return_status == FILE_RETRY)
goto retry_src_stat;
return return_status;
}
#ifndef OS2_NT
if (is_in_linklist (parent_dirs, s, &cbuf)) {
/* we found a cyclic symbolic link */
message_2s (1, MSG_ERROR, _(" Cannot copy cyclic symbolic link \n `%s' "), s);
return FILE_SKIP;
}
#endif
lp = xmalloc (sizeof (struct link), "parent_dirs");
lp->vfs = vfs_type (s);
lp->ino = cbuf.st_ino;
lp->dev = cbuf.st_dev;
lp->next = parent_dirs;
parent_dirs = lp;
/* Now, check if the dest dir exists, if not, create it. */
if (mc_stat (d, &buf)){
/* Here the dir doesn't exist : make it !*/
if (move_over) {
if (mc_rename (s, d) == 0) {
free (parent_dirs);
return FILE_CONT;
}
}
dest_dir = copy_strings (d, 0);
} else {
/*
* If the destination directory exists, we want to copy the whole
* directory, but we only want this to happen once.
*
* Escape sequences added to the * to avoid compiler warnings.
* so, say /bla exists, if we copy /tmp/\* to /bla, we get /bla/tmp/\*
* or ( /bla doesn't exist ) /tmp/\* to /bla -> /bla/\*
*/
#if 1
/* Again, I'm getting curious. Is not d already what we wanted, incl.
* masked source basename? Is not this just a relict of the past versions?
* I'm afraid this will lead into a two level deep dive :(
*
* I think this is indeed the problem. I can not remember any case where
* we actually would like that behaviour -miguel
*
* It's a documented feature (option `Dive into subdir if exists' in the
* copy/move dialog). -Norbert
*/
if (toplevel && dive_into_subdirs){
dest_dir = concat_dir_and_file (d, x_basename (s));
} else
#endif
{
dest_dir = copy_strings (d, 0);
goto dont_mkdir;
}
}
retry_dst_mkdir:
if (my_mkdir (dest_dir, (cbuf.st_mode & umask_kill) | S_IRWXU)){
return_status = file_error (_(" Cannot create target directory \"%s\" \n %s "), dest_dir);
if (return_status == FILE_RETRY)
goto retry_dst_mkdir;
goto ret;
}
lp = xmalloc (sizeof (struct link), "dest_dirs");
mc_stat (dest_dir, &buf);
lp->vfs = vfs_type (dest_dir);
lp->ino = buf.st_ino;
lp->dev = buf.st_dev;
lp->next = dest_dirs;
dest_dirs = lp;
#ifndef OS2_NT
if (preserve_uidgid) {
retry_dst_chown:
if (mc_chown (dest_dir, cbuf.st_uid, cbuf.st_gid)){
return_status = file_error
(_(" Cannot chown target directory \"%s\" \n %s "), dest_dir);
if (return_status == FILE_RETRY)
goto retry_dst_chown;
goto ret;
}
}
#endif
dont_mkdir:
/* open the source dir for reading */
if ((reading = mc_opendir (s)) == 0){
goto ret;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -