File: cmd_symlink.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 (252 lines) | stat: -rw-r--r-- 7,794 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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*
** 1999-05-29 -	A command analogous to Copy, but not quite. Instead of copying the selected source files to
**		the destination directory, this command creates a link at the destination, pointing to the
**		source. Pretty cool. This module also implements the SymLinkEdit command, which can be used
**		to create (!) and edit symbolic links.
*/

#include "gentoo.h"

#include "cmdarg.h"
#include "dialog.h"
#include "dirpane.h"
#include "errors.h"
#include "fileutil.h"
#include "guiutil.h"
#include "overwrite.h"
#include "strutil.h"
#include "cmd_delete.h"
#include "cmd_generic.h"
#include "cmd_symlink.h"

/* ----------------------------------------------------------------------------------------- */

typedef struct {		/* Symbolic link editing info. */
	GtkWidget	*vbox;
	GtkWidget	*name;		/* Entry for the name of the link (not editable unless creating new link). */
	GtkWidget	*contents;	/* Entry for the contents of the link (with pick button for coolness). */
	GtkWidget	*fsel;		/* File selector optionally used to set contents. */

	MainInfo	*min;
	DirPane		*src;
} SleInfo;

/* ----------------------------------------------------------------------------------------- */

/* 1999-05-30 -	Create a link called <name>, pointing at <contents>. If anything already
**		exists under the name <name>, that anything will be silently deleted.
*/
static gboolean set_link(MainInfo *min, const gchar *name, const gchar *contents)
{
	struct stat	stbuf;

	if(lstat(name, &stbuf) == 0)
	{
		gboolean	ok;

		if(S_ISDIR(stbuf.st_mode))
			ok = del_delete_directory(min, name);
		else
			ok = del_delete_file(min, name);
		if(!ok)
		{
			err_show(min);
			return FALSE;
		}
	}
	return (symlink(contents, name) == 0) ? TRUE : FALSE;
}

/* 1999-05-29 -	Create (absolute) symbolic links for all selected entries in <src> at <dst>. */
int cmd_symlink(MainInfo *min, DirPane *src, DirPane *dst, CmdArg *ca)
{
	gchar	dest[PATH_MAX];
	GSList	*slist, *iter;
	OvwRes	res;
	guint	num = 0;

	err_clear(min);

	if((src == NULL) || (dst == NULL))
		return 1;

	if((slist = dp_get_selection(src)) == NULL)
		return 1;

	ovw_overwrite_begin(min, "\"%s\" exists - overwrite?", 0UL);
	for(iter = slist; iter != NULL; iter = g_slist_next(iter))
	{
		g_snprintf(dest, sizeof dest, "%s/%s", dst->dir.path, DP_SEL_NAME(iter));
		res = ovw_overwrite_file(min, dest, dp_full_name(src, DP_SEL_INDEX(src, iter)));
		if(res == OVW_SKIP)
			continue;
		else if(res == OVW_CANCEL)
			break;

		if(set_link(min, dest, dp_full_name(src, DP_SEL_INDEX(src, iter))))
		{
			dp_unselect(src, DP_SEL_INDEX(src, iter));
			num++;
		}
		else
		{
			err_set(min, errno, "SymLink", DP_SEL_NAME(iter));
			err_show(min);
			break;
		}
	}
	ovw_overwrite_end(min);
	dp_free_selection(slist);

	if(num)
		dp_rescan(dst);

	return errno == 0;
}

/* ----------------------------------------------------------------------------------------- */

/* 1999-05-30 -	Update generic command dialog for a new link. */
static void link_body(MainInfo *min, DirPane *src, DirRow *row, GtkWindow *win, gpointer user)
{
	SleInfo	*sle = user;

	gtk_window_set_title(win, "Edit Symbolic Link");
	gtk_entry_set_text(GTK_ENTRY(sle->name), DP_ROW_NAME(row));
	gtk_entry_set_text(GTK_ENTRY(sle->contents), DP_ROW_LINKNAME(row));
	gtk_entry_select_region(GTK_ENTRY(sle->contents), 0, -1);
	gtk_widget_grab_focus(sle->contents);
}

/* 1999-05-30 -	Change a link. */
static int link_action(MainInfo *min, DirPane *src, DirPane *dst, DirRow *row, gpointer user)
{
	gchar		buf[PATH_MAX];
	SleInfo		*sle = user;
	const gchar	*name, *contents;

	name = gtk_entry_get_text(GTK_ENTRY(sle->name));
	g_snprintf(buf, sizeof buf, "%s/%s", src->dir.path, name);
	contents = gtk_entry_get_text(GTK_ENTRY(sle->contents));

	if(set_link(min, buf, contents))
	{
		dp_unselect(src, DP_ROW_INDEX(src, row));
		return TRUE;
	}
	return FALSE;
}

/* 1999-05-30 -	Free the link GUI when the generic module is done with it. */
static void link_free(gpointer user)
{
	SleInfo	*sle = user;

	gtk_widget_destroy(sle->vbox);
	sle->vbox = NULL;
}

/* 1999-05-30 -	User clicked "OK" in file selector. Grab selection, and close it. */
static void evt_fsel_ok_clicked(GtkWidget *btn, gpointer user)
{
	SleInfo	*sle = user;

	gtk_entry_set_text(GTK_ENTRY(sle->contents), gtk_file_selection_get_filename(GTK_FILE_SELECTION(sle->fsel)));
	gtk_grab_remove(sle->fsel);
	gtk_widget_destroy(sle->fsel);
}

static void evt_fsel_cancel_clicked(GtkWidget *wid, gpointer user)
{
	SleInfo	*sle = user;

	gtk_grab_remove(sle->fsel);
	gtk_widget_destroy(sle->fsel);
}

/* 1999-05-30 -	User clicked the "details" button for setting link target from file selector. Pop it up. */
static void evt_pick_clicked(GtkWidget *wid, gpointer user)
{
	gchar	buf[PATH_MAX], *text;
	SleInfo	*sle = user;

	sle->fsel = gtk_file_selection_new("Select Link Target");
	if(((text = gtk_entry_get_text(GTK_ENTRY(sle->contents))) != NULL) && (*text != '\0'))
		g_snprintf(buf, sizeof buf, "%s", text);
	else
		g_snprintf(buf, sizeof buf, "%s/", sle->src->dir.path);
	gtk_file_selection_set_filename(GTK_FILE_SELECTION(sle->fsel), buf);
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(sle->fsel)->ok_button), "clicked", GTK_SIGNAL_FUNC(evt_fsel_ok_clicked), sle);
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(sle->fsel)->cancel_button), "clicked", GTK_SIGNAL_FUNC(evt_fsel_cancel_clicked), sle);
	gtk_widget_show(sle->fsel);
	gtk_grab_add(sle->fsel);
}

/* 1999-05-30 -	Edit all selected symbolic links one at a time, or, if there is no selection,
**		create a new link letting the user type both source and destination names.
*/
int cmd_symlinkedit(MainInfo *min, DirPane *src, DirPane *dst, CmdArg *ca)
{
	static SleInfo	sle;
	GtkWidget	*label, *table, *pick;

	sle.min = min;
	sle.src = src;

	sle.vbox = gtk_vbox_new(FALSE, 0);
	table = gtk_table_new(2, 3, FALSE);
	label = gtk_label_new("Name");
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,  0,0,0,0);
	gtk_widget_show(label);
	sle.name = gtk_entry_new_with_max_length(FILENAME_MAX - 1);
	gtk_table_attach(GTK_TABLE(table), sle.name, 1, 3, 0, 1,  GTK_EXPAND|GTK_FILL,0,0,0);
	gtk_widget_show(sle.name);
	label = gtk_label_new("Contents");
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,  0,0,0,0);
	gtk_widget_show(label);
	sle.contents = gtk_entry_new_with_max_length(PATH_MAX - 1);
	gtk_table_attach(GTK_TABLE(table), sle.contents, 1, 2, 1, 2,  GTK_EXPAND|GTK_FILL,0,0,0);
	gtk_widget_show(sle.contents);
	pick = gui_details_button_new(min->gui->window->window);
	gtk_signal_connect(GTK_OBJECT(pick), "clicked", GTK_SIGNAL_FUNC(evt_pick_clicked), &sle);
	gtk_table_attach(GTK_TABLE(table), pick, 2, 3, 1, 2,  0,0,0,0);
	gtk_widget_show(pick);
	gtk_box_pack_start(GTK_BOX(sle.vbox), table, TRUE, TRUE, 0);
	gtk_widget_show(table);
	gtk_widget_show(sle.vbox);

	if(dp_has_selection(src))
	{
		gtk_entry_set_editable(GTK_ENTRY(sle.name), FALSE);
		return cmd_generic(min, CGF_NOALL | CGF_SRC | CGF_LINKSONLY, link_body, link_action, link_free, &sle);
	}
	else
	{
		Dialog	*dlg;

		dlg = dlg_dialog_sync_new(sle.vbox, "Create Symbolic Link", "OK|Cancel");
		gtk_widget_grab_focus(sle.name);
		if(dlg_dialog_sync_wait(dlg) == DLG_POSITIVE)
		{
			gchar	buf[PATH_MAX], *name, *contents;
			OvwRes	ores;

			name = gtk_entry_get_text(GTK_ENTRY(sle.name));
			if(strchr(name, G_DIR_SEPARATOR) != NULL)
				str_strncpy(buf, name, sizeof buf);
			else
				g_snprintf(buf, sizeof buf, "%s/%s", src->dir.path, name);
			contents = gtk_entry_get_text(GTK_ENTRY(sle.contents));
			ovw_overwrite_begin(min, "\"%s\" exists - overwrite?", 0UL);
			ores = ovw_overwrite_file(min, buf, NULL);
			if(ores == OVW_PROCEED)
			{
				if(set_link(min, buf, contents))
					dp_rescan(src);
			}
			ovw_overwrite_end(min);
		}
		dlg_dialog_sync_destroy(dlg);
	}
	return 1;
}