1
/* Copyright 2001, 2002 Manuel Arriaga
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
static int rename_handle_error(const char *oldpath, const char *newpath,
29
int (*real_rename) (const char*, const char*), int in_case_of_failure);
31
/* When can rename() cause data loss?
32
* When both its arguments refer to existing files, then the original file
33
* at newpath will be lost.
35
* What this version of rename() does: if a file already exists at newpath, we move it
36
* (with the "real" rename()) to the trash can and then hand over control to GNU libc's
39
* We also take care so that, if we fail, errno is either zero (if a
40
* "libtrash-specific" error occurred) or has a meaningful value which the
41
* caller should know how to interpret after a call to rename(). This way,
42
* we avoid confusing the caller with a errno set by some other GNU libc
43
* function used by the libtrash wrapper.
47
int rename(const char *oldpath, const char *newpath)
50
struct stat path_stat;
52
char *absolute_newpath = NULL;
65
fprintf(stderr, "\nEntering rename().\n");
69
/* First we call init(), which will set the configuration variables: */
73
/* We always call fini() before quitting. */
75
/* If real_rename_unavailable is set, we must return -1 because there's nothing else we can do: */
77
if (cfg.real_rename_unavailable)
80
fprintf(stderr, "real_rename_unavailable is set.\nrename returning -1.\n");
82
errno = 0; /* we set errno to zero so that, if errno was previously set to some other value, it
83
doesn't confuse the caller. */
89
/* If libtrash_off or rename_off is set, the user has asked us to become temporarily inactive an let the real
90
* rename() perform its task.*/
92
if (cfg.libtrash_off || cfg.rename_off)
95
fprintf(stderr, "Passing request to rename(%s, %s) to the real rename() because (libtrash|rename)_off is set.\n",
99
return (*cfg.real_rename) (oldpath, newpath); /* real rename() sets errno. */
104
/* If general_failure is set, we know that something went wrong in _init, and we do whatever in_case_of_failure
105
* specifies, returning the appropriate error code.*/
107
if (cfg.general_failure)
110
fprintf(stderr, "general_failure is set in rename(), invoking rename_handle_error().\n"
111
"in_case_of_failure has value %d.\n", cfg.in_case_of_failure);
114
return rename_handle_error(oldpath, newpath, cfg.real_rename, cfg.in_case_of_failure); /* either the real rename() sets errno, or we return -1 and errno is
119
/* First of all: does a file called newpath already exist? If it doesn't (or if it is a dir), we don't need to
123
error = lstat(newpath, &path_stat);
125
if ( (error && errno == ENOENT) ||
126
(!error && S_ISDIR(path_stat.st_mode)) )
129
fprintf(stderr, "newpath (%s) either doesn't exit or is a directory.\nCalling the \"real\" rename().\n", newpath);
132
return (*cfg.real_rename) (oldpath, newpath); /* errno set by real rename(). */
136
/* We don't protect symbolic links, except if they are under one of the protected directories; therefore, we must
137
* postpone the decision about whether to ignore a file because it is a symlink until we know if it is "protected":
140
if (!error && S_ISLNK(path_stat.st_mode))
146
/* Second: does a file called oldpath exist? If it doesn't (or if it is a dir), there's nothing for us to do, because
147
the real call to rename() will necessarily fail (explanation: if oldpath is a dir, we can be sure that the rename()
148
will fail because a _file_ called newpath already exists, and rename() doesn't overwrite files so that it can
149
successfully rename dirs):
152
error = lstat(oldpath, &path_stat);
154
if ( (error && errno == ENOENT) || (!error && S_ISDIR(path_stat.st_mode)) )
157
fprintf(stderr, "oldpath (%s) either doesn't exist or is a directory.\nCalling the \"real\" rename().\n", oldpath);
160
return (*cfg.real_rename) (oldpath, newpath); /* errno set by real rename() */
165
/* Even if both files exist, are we sure that we have write-access
166
* to the directory the file called oldpath is found in? If we don't
167
* have it (either due to lacking write-permission or due to the fact
168
* that oldpath points to a file on a read-only filesystem), then the
169
* call to the "real" rename() will fail and we will end up just moving
170
* the file presently at newpath to the trash can, unless we exit at
173
* How might this happen? If we can write to the dir in which newpath is
174
* found, but not to the one which holds oldpath, we will successfully
175
* move the file presently found at newpath to the trash can and then
176
* once again invoke rename() to move the file called oldpath from
177
* oldpath to newpath; but this second call to rename() will fail and
178
* the user will end up with the file originally called newpath in the
179
* trash can, and the file called old_path in the same place.
181
* For this reason, we call the real rename() right away and let it
182
* (fail and) complain about insufficient permissions / a RO FS.
184
* Two notes on can_write_to_dir(): (1st) if it fails due to an internal
185
* error, it returns TRUE, so that rename() doesn't exit at this point
186
* (it behaves this way because, if an error occurrs, we prefer to make
187
* an unnecessary copy of a file over the possibility of NOT making a
188
* NECESSARY one) (2nd) can_write_to_dir() performs the permissions
189
* check with the _effective_ UID rather than the real one, so that
190
* SETUID programs work correctly (of course, we are assuming that the
191
* program already did the appropriate permission checks -that's its
192
* responsability). */
194
if (!can_write_to_dir(oldpath))
197
fprintf(stderr, "We don't have write-access to the dir which contains oldpath (%s).\n"
198
"Calling the \"real\" rename().\n", oldpath);
201
return (*cfg.real_rename) (oldpath, newpath); /* errno set by real rename() */
206
/* By now we know that our services are needed: rename(oldpath, newpath) might cause the loss of the file originally
207
* called newpath, because both exist and we have write-permission to the dirs which contain them.
211
/* Let us begin by building an absolute path, if we weren't passed one: */
213
/* [If no error occurred, memory was dynamically allocated and it is now pointed to by absolute_newpath.
214
That is the reason why we free absolute_newpath before returning.] */
216
/* We don't use GNU libc's canonicalize_file_name() directly for reasons explained in unlink.c: */
218
absolute_newpath = build_absolute_path(newpath);
220
if (!absolute_newpath)
223
fprintf(stderr, "Unable to build absolute_newpath.\nInvoking rename_handle_error().\n");
226
return rename_handle_error(oldpath, newpath, cfg.real_rename,
227
cfg.in_case_of_failure); /* errno set either by the real rename() or set to 0 (just like the other
228
* call to rename_handle_error() above). */
233
/* Independently of the way in which the argument was written, absolute_newpath now holds the absolute
234
* path to the new filename, free of any "/../" or "/./". */
237
fprintf(stderr, "CLEANSED ABSOLUTE_NEWPATH: |%s|\n", absolute_newpath);
243
/* By now we want to know whether the file at newpath "qualifies" to be stored in the trash can rather than
244
permanently lost (another possible option is this file being considered "unremovable"). This decision is
245
taken according to the user's preferences by the function decide_action(): */
248
file_should = decide_action(absolute_newpath, &cfg);
256
fprintf(stderr, "decide_action() told rename() to permanently destroy file %s.\n", absolute_newpath);
259
retval = (*cfg.real_rename) (oldpath, newpath); /* errno set by real rename() */
264
case BE_LEFT_UNTOUCHED:
267
fprintf(stderr, "decide_action() told rename() to leave file %s untouched.\n", absolute_newpath);
270
/* Set errno so that the caller interprets this failure as "insufficient permissions": */
282
fprintf(stderr, "decide_action() told rename() to save a copy of file %s.\n", absolute_newpath);
285
/* But if it is a symlink we refuse to "save" it nonetheless: */
290
fprintf(stderr, " but its suggestion is being ignored because %s is just a symlink.\n", absolute_newpath);
292
retval = (*cfg.real_rename) (oldpath, newpath); /* real rename() sets errno. */
294
else /* if absolute_newpath isn't a symlink */
296
/* (See below for information on this code.) */
298
if (found_under_dir(absolute_newpath, cfg.home)) /* (a) */
299
error = graft_file(cfg.absolute_trash_can, absolute_newpath, cfg.home, &cfg);
301
error = graft_file(cfg.absolute_trash_system_root, absolute_newpath, NULL, &cfg);
303
if (error) /* graft_file() failed. */
306
fprintf(stderr, "graft_file() failed, invoking rename_handle_error().\n");
308
retval = rename_handle_error(oldpath, newpath, cfg.real_rename,
309
cfg.in_case_of_failure); /* about errno: see explanation near the previous call to
310
* rename_handle_error(). */
312
else /* graft_file() succeeded, we just need to perform the "real" operation: */
315
fprintf(stderr, "graft_file(), called by rename(), succeeded.\n");
317
retval = (*cfg.real_rename) (oldpath, newpath); /* real rename() setting errno. */
327
/* About the code in case BE_SAVED: (a) a file under the user's home dir and (b) a file outside of the user's home
328
dir with global_protection set. We then pass our arguments to the
329
"real" rename(), now that the file originally at newpath is safely
330
stored in the user's trash can. If graft_file() failed (and a copy of
331
the file ISN'T safely stored in the user's trash can), we invoke
332
rename_handle_error() which will act based on the value the user chose
333
for in_case_of_failure. */
335
/* Free memory before quitting: */
337
free(absolute_newpath);
340
return retval; /* By now, errno has been set to a meaningful value in one of the cases above. */
344
/* ------------------------------------------------------------------------------------ */
346
/* This function is called by rename() in case an error is spotted. It does what the user
347
* told us to do in these situations (through the variable in_case_of_failure), and rename() just
348
* returns the value passed by rename_trash_error():
352
static int rename_handle_error(const char *oldpath, const char *newpath,
353
int (*real_rename) (const char*, const char*), int in_case_of_failure)
355
if (in_case_of_failure == ALLOW_DESTRUCTION)
356
return (*real_rename) (oldpath, newpath); /* real rename() sets errno */
357
else /* if (in_case_of_failure == PROTECT) */