📄 file.c
字号:
while ((next = mc_readdir (reading)) && return_status != FILE_ABORT){
/*
* Now, we don't want '.' and '..' to be created / copied at any time
*/
if (!strcmp (next->d_name, "."))
continue;
if (!strcmp (next->d_name, ".."))
continue;
/* get the filename and add it to the src directory */
path = concat_dir_and_file (s, next->d_name);
(*xstat)(path, &buf);
if (S_ISDIR (buf.st_mode)){
mdpath = concat_dir_and_file (dest_dir, next->d_name);
/*
* From here, we just intend to recursively copy subdirs, not
* the double functionality of copying different when the target
* dir already exists. So, we give the recursive call the flag 0
* meaning no toplevel.
*/
return_status = copy_dir_dir (path, mdpath, 0, 0, delete, parent_dirs);
free (mdpath);
} else {
dest_file = concat_dir_and_file (dest_dir, x_basename (path));
return_status = copy_file_file (path, dest_file, 1);
free (dest_file);
}
if (delete && return_status == FILE_CONT) {
if (erase_at_end) {
static struct link *tail;
lp = xmalloc (sizeof (struct link) + strlen (path), "erase_list");
strcpy (lp->name, path);
lp->st_mode = buf.st_mode;
lp->next = 0;
if (erase_list) {
tail->next = lp;
tail = lp;
} else
erase_list = tail = lp;
} else {
if (S_ISDIR (buf.st_mode)) {
return_status = erase_dir_iff_empty (path);
} else
return_status = erase_file (path);
}
}
#ifdef __os2__
/* The OS/2 mc_readdir returns a block of memory DIR
* next should be freed: .ado
*/
if (!next)
free (next);
#endif
free (path);
}
mc_closedir (reading);
/* .ado: Directories can not have permission set in OS/2 */
#ifndef __os2__
if (preserve) {
mc_chmod (dest_dir, cbuf.st_mode & umask_kill);
utb.actime = cbuf.st_atime;
utb.modtime = cbuf.st_mtime;
mc_utime(dest_dir, &utb);
}
#endif
ret:
free (dest_dir);
free (parent_dirs);
return return_status;
}
/* }}} */
/* {{{ Move routines */
int
move_file_file (char *s, char *d)
{
struct stat src_stats, dst_stats;
int return_status = FILE_CONT;
if (show_source (s) == FILE_ABORT
|| show_target (d) == FILE_ABORT)
return FILE_ABORT;
mc_refresh ();
retry_src_lstat:
if (mc_lstat (s, &src_stats) != 0){
/* Source doesn't exist */
return_status = file_error (_(" Cannot stat file \"%s\" \n %s "), s);
if (return_status == FILE_RETRY)
goto retry_src_lstat;
return return_status;
}
if (mc_lstat (d, &dst_stats) == 0){
/* Destination already exists */
/* .ado: for OS/2 and NT, no st_ino exists */
#ifndef OS2_NT
if (src_stats.st_dev == dst_stats.st_dev
&& src_stats.st_ino == dst_stats.st_ino){
int msize = COLS - 36;
char st[MC_MAXPATHLEN];
char dt[MC_MAXPATHLEN];
if (msize < 0)
msize = 40;
msize /= 2;
strcpy (st, name_trunc (s, msize));
strcpy (dt, name_trunc (d, msize));
message_3s (1, MSG_ERROR, _(" `%s' and `%s' are the same file "),
st, dt );
do_refresh ();
return FILE_SKIP;
}
#endif /* OS2_NT */
if (S_ISDIR (dst_stats.st_mode)){
message_2s (1, MSG_ERROR, _(" Cannot overwrite directory `%s' "), d);
do_refresh ();
return FILE_SKIP;
}
if (confirm_overwrite){
if (vfs_file_is_ftp (s))
do_reget = -1;
else
do_reget = 0;
return_status = query_replace (d, &src_stats, &dst_stats);
if (return_status != FILE_CONT)
return return_status;
}
/* Ok to overwrite */
}
#if 0
retry_rename:
#endif
if (!do_append) {
if (S_ISLNK (src_stats.st_mode) && stable_symlinks) {
if ((return_status = make_symlink (s, d)) == FILE_CONT)
goto retry_src_remove;
else
return return_status;
}
if (mc_rename (s, d) == 0)
return FILE_CONT;
}
#if 0
/* Comparison to EXDEV seems not to work in nfs if you're moving from
one nfs to the same, but on the server it is on two different
filesystems. Then nfs returns EIO instead of EXDEV.
Hope it will not hurt if we always in case of error try to copy/delete. */
else
errno = EXDEV; /* Hack to copy (append) the file and then delete it */
if (errno != EXDEV){
return_status = files_error (_(" Cannot move file \"%s\" to \"%s\" \n %s "), s, d);
if (return_status == FILE_RETRY)
goto retry_rename;
return return_status;
}
#endif
/* Failed because filesystem boundary -> copy the file instead */
if ((return_status = copy_file_file (s, d, 0)) != FILE_CONT)
return return_status;
if ((return_status = show_source (NULL)) != FILE_CONT
|| (return_status = show_file_progress (0, 0)) != FILE_CONT)
return return_status;
mc_refresh ();
retry_src_remove:
if (mc_unlink (s)){
return_status = file_error (_(" Cannot remove file \"%s\" \n %s "), s);
if (return_status == FILE_RETRY)
goto retry_src_remove;
return return_status;
}
return FILE_CONT;
}
int
move_dir_dir (char *s, char *d)
{
struct stat sbuf, dbuf, destbuf;
struct link *lp;
char *destdir;
int return_status;
int move_over = 0;
if (show_source (s) == FILE_ABORT
|| show_target (d) == FILE_ABORT)
return FILE_ABORT;
mc_refresh ();
mc_stat (s, &sbuf);
if (mc_stat (d, &dbuf))
destdir = copy_strings (d, 0); /* destination doesn't exist */
else if (!dive_into_subdirs) {
destdir = copy_strings (d, 0);
move_over = 1;
} else
destdir = concat_dir_and_file (d, x_basename (s));
/* Check if the user inputted an existing dir */
retry_dst_stat:
if (!mc_stat (destdir, &destbuf)){
if (move_over) {
if ((return_status = copy_dir_dir (s, destdir, 0, 1, 1, 0)) != FILE_CONT)
goto ret;
goto oktoret;
} else {
if (S_ISDIR (destbuf.st_mode))
return_status = file_error (_(" Cannot overwrite directory \"%s\" %s "), destdir);
else
return_status = file_error (_(" Cannot overwrite file \"%s\" %s "), destdir);
if (return_status == FILE_RETRY)
goto retry_dst_stat;
}
free (destdir);
return return_status;
}
retry_rename:
if (mc_rename (s, destdir) == 0){
return_status = FILE_CONT;
goto ret;
}
/* .ado: Drive, Do we need this anymore? */
#ifdef WIN32
else {
/* EXDEV: cross device; does not work everywhere */
if (toupper(s[0]) != toupper(destdir[0]))
goto w32try;
}
#endif
if (errno != EXDEV){
return_status = files_error (_(" Cannot move directory \"%s\" to \"%s\" \n %s "), s, d);
if (return_status == FILE_RETRY)
goto retry_rename;
goto ret;
}
w32try:
/* Failed because of filesystem boundary -> copy dir instead */
if ((return_status = copy_dir_dir (s, destdir, 0, 0, 1, 0)) != FILE_CONT)
goto ret;
oktoret:
if ((return_status = show_source (NULL)) != FILE_CONT
|| (return_status = show_file_progress (0, 0)) != FILE_CONT)
goto ret;
mc_refresh ();
if (erase_at_end) {
for ( ; erase_list && return_status != FILE_ABORT; ) {
if (S_ISDIR (erase_list->st_mode)) {
return_status = erase_dir_iff_empty (erase_list->name);
} else
return_status = erase_file (erase_list->name);
lp = erase_list;
erase_list = erase_list->next;
free (lp);
}
}
erase_dir_iff_empty (s);
ret:
free (destdir);
for ( ; erase_list; ) {
lp = erase_list;
erase_list = erase_list->next;
free (lp);
}
return return_status;
}
/* }}} */
/* {{{ Erase routines */
static int
erase_file (char *s)
{
int return_status;
if (show_deleting (s) == FILE_ABORT)
return FILE_ABORT;
mc_refresh ();
retry_unlink:
if (mc_unlink (s)){
return_status = file_error (_(" Cannot delete file \"%s\" \n %s "), s);
if (return_status == FILE_RETRY)
goto retry_unlink;
return return_status;
}
return FILE_CONT;
}
static int
recursive_erase (char *s)
{
struct dirent *next;
struct stat buf;
DIR *reading;
char *path;
int return_status = FILE_CONT;
if (!strcmp (s, ".."))
return 1;
reading = mc_opendir (s);
if (!reading)
return 1;
while ((next = mc_readdir (reading)) && return_status == FILE_CONT){
if (!strcmp (next->d_name, "."))
continue;
if (!strcmp (next->d_name, ".."))
continue;
path = concat_dir_and_file (s, next->d_name);
if (mc_lstat (path, &buf)){
free (path);
return 1;
}
if (S_ISDIR (buf.st_mode))
return_status = (recursive_erase (path) != FILE_CONT);
else
return_status = erase_file (path);
free (path);
/* .ado: OS/2 returns a block of memory DIR to next and must be freed */
#ifdef __os2__
if (!next)
free (next);
#endif
}
mc_closedir (reading);
if (return_status != FILE_CONT)
return return_status;
if (show_deleting (s) == FILE_ABORT)
return FILE_ABORT;
mc_refresh ();
retry_rmdir:
if (my_rmdir (s)){
return_status = file_error (_(" Cannot remove directory \"%s\" \n %s "), s);
if (return_status == FILE_RETRY)
goto retry_rmdir;
return return_status;
}
return FILE_CONT;
}
/* Return -1 on error, 1 if there are no entries besides "." and ".."
in the directory path points to, 0 else. */
static int
check_dir_is_empty(char *path)
{
DIR *dir;
struct dirent *d;
int i;
dir = mc_opendir (path);
if (!dir)
return -1;
for (i = 1, d = mc_readdir (dir); d; d = mc_readdir (dir)) {
if (d->d_name[0] == '.' && (d->d_name[1] == '\0' ||
(d->d_name[1] == '.' && d->d_name[2] == '\0')))
continue; /* "." or ".." */
i = 0;
break;
}
mc_closedir (dir);
return i;
}
int
erase_dir (char *s)
{
int error;
if (strcmp (s, "..") == 0)
return FILE_SKIP;
if (strcmp (s, ".") == 0)
return FILE_SKIP;
if (show_deleting (s) == FILE_ABORT)
return FILE_ABORT;
mc_refresh ();
/* The old way to detect a non empty directory was:
error = my_rmdir (s);
if (error && (errno == ENOTEMPTY || errno == EEXIST))) {
For the linux user space nfs server (nfs-server-2.2beta29-2)
we would have to check also for EIO. I hope the new way is
fool proof. (Norbert)
*/
error = check_dir_is_empty (s);
if (error == 0) { /* not empty */
error = query_recursive (s);
if (error == FILE_CONT)
return recursive_erase (s);
else
return error;
}
retry_rmdir:
error = my_rmdir (s);
if (error == -1){
error = file_error (_(" Cannot remove directory \"%s\" \n %s "), s);
if (error == FILE_RETRY)
goto retry_rmdir;
return error;
}
return FILE_CONT;
}
int
erase_dir_iff_empty (char *s)
{
int error;
if (strcmp (s, "..") == 0)
return FILE_SKIP;
if (strcmp (s, ".") == 0)
return FILE_SKIP;
if (show_deleting (s) == FILE_ABORT)
return FILE_ABORT;
mc_refresh ();
if (1 != check_dir_is_empty (s)) /* not empty or error */
return FILE_CONT;
retry_rmdir:
error = my_rmdir (s);
if (error) {
error = file_error (_(" Cannot remove directory \"%s\" \n %s "), s);
if (error == FILE_RETRY)
goto retry_rmdir;
return error;
}
return FILE_CONT;
}
/* }}} */
/* {{{ Panel operate routines */
/* Returns currently selected file or the first marked file if there is one */
static char *
get_file (WPanel *panel, struct stat *stat_buf)
{
int i;
/* No problem with Gnome, as get_current_type never returns view_tree there */
if (get_current_type () == view_tree){
WTree *tree = (WTree *)get_panel_widget (get_current_index ());
mc_stat (tree->selected_ptr->name, stat_buf);
return tree->selected_ptr->name;
}
if (panel->marked){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -