File: cmd_move.c

package info (click to toggle)
gentoo 0.11.10-3
  • links: PTS
  • area: main
  • in suites: potato
  • size: 3,116 kB
  • ctags: 2,901
  • sloc: ansic: 23,849; makefile: 195
file content (187 lines) | stat: -rw-r--r-- 5,305 bytes parent folder | download
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;
}