1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
/*
** 1998-05-30 - Implementation of the built-in MOVE command, which is used to, er, move
** files and directories. It might become incredibly involved. We'll see
** about that.
** 1998-09-12 - Did changes in command arguments to ease implementation of MOVEAS, also
** exported all the move_XXX() functions, as the cmd_copy module does.
** 1999-03-06 - Adapted for new selection/dirrow representations.
*/
#include "gentoo.h"
#include "errors.h"
#include "dirpane.h"
#include "fileutil.h"
#include "overwrite.h"
#include "progress.h"
#include "cmd_copy.h"
#include "cmd_move.h"
#define CMD_ID "move"
/* ----------------------------------------------------------------------------------------- */
/* 1998-09-12 - Modified: now <to> is the full destination name. */
int move_file(MainInfo *min, const gchar *from, const gchar *to, struct stat *sstat)
{
if(copy_file(min, from, to, sstat))
unlink(from);
return errno == 0;
}
/* 1998-09-12 - Modified: now <to> is the complete destination name. */
int move_device(MainInfo *min, const gchar *from, const gchar *to, struct stat *sstat)
{
if(copy_device(min, from, to, sstat))
unlink(from);
return errno == 0;
}
/* 1998-06-07 - Move a symbolic link. Will check if the link is "explicit", i.e. if it contains a full path
** name, and then compare that name to the directory it is residing in. On match, a translation
** is done so that the new link (created at the destination) is correct.
** 1998-09-12 - Modified; now <to> is the full destination name, rather than just the dir.
*/
int move_link(MainInfo *min, const gchar *from, const gchar *to)
{
if(copy_link(min, from, to))
unlink(from);
return errno == 0;
}
/* 1998-06-07 - Move a directory full of stuff. Does not simply call copy_dir from the cmd_copy module,
** since that would require also calling del_dir (from cmd_delete). I feel that is just too
** ineffecient, having to traverse twice.
** 1998-09-12 - Modified: now <to> is the complete destination name, since this is the new deal.
*/
int move_dir(MainInfo *min, const gchar *from, const gchar *to)
{
char old_dir[PATH_MAX];
DIR *dir;
struct dirent *de;
struct stat stat;
if(lstat(from, &stat) != 0)
{
err_set(min, errno, CMD_ID, from);
return 0;
}
if(fut_cd(from, old_dir, sizeof old_dir))
{
if(mkdir(to, stat.st_mode | S_IWUSR) == 0)
{
if((dir = opendir(".")) != NULL)
{
while(!errno && (de = readdir(dir)) != NULL)
{
if(!min->cfg.dir_filter(de->d_name))
continue;
if(lstat(de->d_name, &stat) == 0)
{
gchar dest2[PATH_MAX];
g_snprintf(dest2, sizeof dest2, "%s/%s", to, de->d_name);
if(S_ISDIR(stat.st_mode))
move_dir(min, de->d_name, dest2);
else if(S_ISREG(stat.st_mode))
move_file(min, de->d_name, dest2, &stat);
else if(S_ISLNK(stat.st_mode))
move_link(min, de->d_name, dest2);
else if(S_ISBLK(stat.st_mode) || S_ISCHR(stat.st_mode))
move_device(min, de->d_name, dest2, &stat);
if(!errno)
rewinddir(dir);
}
}
closedir(dir);
}
}
if(!errno && fut_cd(old_dir, NULL, 0))
rmdir(from);
}
if(errno)
err_set(min, errno, CMD_ID, from);
return errno == 0;
}
/* 1998-07-11 - Bug fix: always failed after first file when moving on the same device. The
** error reporting was also slightly broken.
*/
int cmd_move(MainInfo *min, DirPane *src, DirPane *dst, CmdArg *ca)
{
gchar old_path[PATH_MAX], dest[PATH_MAX], *name = NULL;
guint count = 0;
GSList *slist, *iter;
mode_t mode;
OvwRes ores;
if((src == NULL) || (dst == NULL))
return 1;
if(!fut_cd(src->dir.path, old_path, sizeof old_path))
return 0;
if((slist = dp_get_selection(src)) == NULL)
return 1;
err_clear(min);
ovw_overwrite_begin(min, "\"%s\" already exists - continue with move?", 0UL);
pgs_progress_begin(min, "Move", PFLG_COUNT_RECURSIVE | PFLG_ITEM_VISIBLE | PFLG_BYTE_VISIBLE);
for(iter = slist; !errno && (iter != NULL); iter = g_slist_next(iter))
{
name = DP_SEL_NAME(iter);
g_snprintf(dest, sizeof dest, "%s/%s", dst->dir.path, name);
ores = ovw_overwrite_file(min, dest, dp_full_name(src, DP_SEL_INDEX(src, iter)));
if(ores == OVW_SKIP)
continue;
else if(ores == OVW_CANCEL)
break;
mode = DP_SEL_LSTAT(iter).st_mode;
err_clear(min);
if(S_ISLNK(mode))
move_link(min, DP_SEL_NAME(iter), dest);
else
{
if(rename(name, dest) == 0) /* Try a direct rename, very quick. */
count++;
else if(errno == EXDEV)
{
err_clear(min);
if(S_ISLNK(mode))
move_link(min, DP_SEL_NAME(iter), dest);
else if(S_ISREG(mode))
move_file(min, DP_SEL_NAME(iter), dest, &DP_SEL_LSTAT(iter));
else if(S_ISBLK(mode) || S_ISCHR(mode))
move_device(min, DP_SEL_NAME(iter), dest, &DP_SEL_LSTAT(iter));
else if(S_ISDIR(mode))
move_dir(min, DP_SEL_NAME(iter), dest);
else
fprintf(stderr, "Can't move '%s' -- don't know how!\n", DP_SEL_NAME(iter));
count += (errno == 0);
}
else
break;
}
}
pgs_progress_end(min);
ovw_overwrite_end(min);
if(count > 0) /* If any files were moved, update panes. */
{
dp_rescan(src);
dp_rescan(dst);
fut_cd(old_path, NULL, 0);
}
if(errno)
err_set(min, errno, CMD_ID, name);
err_show(min);
dp_free_selection(slist);
return errno == 0;
}
|