// File : /cmds/file/_mv.c
// 93-03-15 : Created by Watcher@TMI-2
// 93-04-09 : Updated by Watcher@TMI-2 to allow silent mv mode and use
// get_dir() instead of the wildcard daemon so dotfiles may
// be properly processed.
// 93-06-23 : Changed by Robocoder@TMI-2 to use file lock daemon
// 93-07-30 : Changed by Grendel@TMI-2 so the valid_write sends "rm"
// as the funcition for the "from" - this is for t the benefit of
// the quota deamon
//
// This is the standard wizard file mv command. It allows
// wildcards, recursive directory tree mv's, and interactive
// flag requests (blocking the default overwrite option).
#include <mudlib.h>
#include <daemons.h>
#include <flock.h>
inherit DAEMON ;
static string get_path(string str, int dir_flag);
static string get_file(string str);
static int mv_file(string from, string to, int rflag, int iflag, int silent);
#define SYNTAX "Syntax: mv [-rsfi] [source] [destination]\n"
int cmd_mv(string str) {
mixed *tmp, *files;
string flags, tpath, fpath, from, to, tmp1, tmp2;
int loop, rflag, iflag, silent, dir_flag;
seteuid( getuid(this_object()) );
notify_fail( SYNTAX );
if(!str || str == "") return 0;
// Check for user requested flags
if(sscanf(str, "-%s %s", flags, str) == 2) {
if(sscanf(" " + flags + " ", "%sr%s", tmp1, tmp2) == 2) rflag = 1;
if(sscanf(" " + flags + " ", "%si%s", tmp1, tmp2) == 2) iflag = 1;
if(sscanf(" " + flags + " ", "%sf%s", tmp1, tmp2) == 2) iflag = 0;
if(sscanf(" " + flags + " ", "%ss%s", tmp1, tmp2) == 2) silent = 1;
}
// Parse into source and destination
if(sscanf(str, "%s to %s", from, to) != 2 &&
sscanf(str, "%s %s", from, to) !=2) return 0;
// Check for use of "." for present dir moving.
if(to == ".") to = (string)this_player()->query("cwd");
// Check to see if dest str is a directory.
if(to[strlen(to)-1] == '/') dir_flag = 1;
// Resolve paths of source and destination requests
from = resolv_path("cwd", from);
to = resolv_path("cwd", to);
// Check for a directory move request
if(from[strlen(from)-1] == '/') {
from += "*";
rflag = 1;
} else if (rflag && directory_exists(from)) {
from += "/*";
}
// Isolate source and destination directories
fpath = get_path(from, 0);
tpath = get_path(to, dir_flag);
// Check for existence of source and dest directories
if(!directory_exists(fpath)) {
write("Mv: No such directory : " + fpath + "\n");
return 1; }
if(!directory_exists(tpath)) {
write("Mv: No such directory : " + tpath + "\n");
return 1; }
// Check user's permissions in source and dest directories
if((int)master()->valid_write(fpath, previous_object(), "rm") == 0) {
printf("Mv: Access denied in %s.\n",
(fpath == "" ? "root directory" : fpath));
return 1; }
if((int)master()->valid_write(tpath, previous_object(), "mv") == 0) {
printf("Mv: Access denied in %s.\n",
(tpath == "" ? "root directory" : tpath));
return 1; }
// Check to see if it's a renaming operation
if (!directory_exists(to) && !rflag && from != to &&
sscanf(tpath, fpath + "%*s") != 1 &&
( (directory_exists(from) && !file_exists(to)) ||
file_exists(from) ) ) {
mv_file(from, to, 0, iflag, 0);
return 1;
}
// Process request for wildcard entry
files = get_dir(from);
if (files) {
files -= ({ ".", ".." });
}
// Check to see if any files match the desired pattern
if(!files || !sizeof(files)) {
write("Mv: No such pattern : " + from + "\n");
return 1; }
// If multiple files, treat 'to' string as destination path
if(sizeof(files) > 1) {
if(tpath != "") tpath = to + "/";
if(!directory_exists(tpath)) {
write("Mv: No such directory : " + tpath + "\n");
return 1; }
// Check to see if source and dest paths are equal.
if(tpath == fpath) {
write("Mv: Requested destination is the same as source files.\n");
return 1; }
}
// Protect against silly users trying to recursively mv files
// farther down the same directory tree. This would cause the
// mv command to try to move files recursively until the disk
// space is filled. :(
if(sscanf(tpath, fpath + "%s", tmp1) == 1 && tmp1 != "" && rflag) {
write("Mv: Illegal to attempt recursive mv to same directory tree.\n");
return 1; }
// If only one file selected ...
if(sizeof(files) == 1) {
if (directory_exists(from))
if (file_exists(to)) {
write("Mv: insufficient magic to move a directory into a file.\n");
return 1;
} else if (directory_exists(to)) {
if (sscanf(to, from +"%*s") == 1) {
write("Mv: Illegal to mv deeper into directory tree.\n");
return 1;
}
to += (tpath == "" ? "" : "/") + get_file(files[0]);
mv_file(from, to, 0, iflag, 0);
return 1;
}
if(!file_exists(fpath + files[0]) &&
!directory_exists(fpath + files[0])) {
write("Mv: " + fpath + files[0] + " does not exist.\n");
return 1; }
if(directory_exists(to))
to += (tpath == "" ? "" : "/") + get_file(files[0]);
mv_file(fpath + files[0], to, rflag, iflag, 0);
this_player()->set("cwf", to);
return 1; }
// Otherwise loop through the multiple file choices
for(loop=0; loop<sizeof(files); loop++)
mv_file(fpath + files[loop], tpath + files[loop], rflag, iflag, silent);
if(silent) write("Mv: File move complete.\n");
return 1; }
static int mv_file(string from, string to, int rflag, int iflag, int silent) {
mixed *tmp;
int loop;
// Block if source and destination are equivalent
if(from == to) {
write("Mv: Requested destination is the same as source file.\n");
return 1; }
// If source file request is a directory
if(directory_exists(from)) {
from += "/";
if(!directory_exists(to)) {
catch( rename(from[0..strlen(from)-2], to) );
if(!silent && rflag)
write("Mv: " + from + " directory moved to " + to + "\n");
return 1;
}
to += "/";
// destination directory already exists...move contents over
tmp = get_dir(from);
// destination directory already exists
for(loop=0; loop<sizeof(tmp); loop++)
mv_file(from + tmp[loop], to + tmp[loop], rflag, iflag, silent);
rmdir(from[0..strlen(from)-2]);
if(!silent)
write("Mv: " + from + " directory moved to " + to + "\n");
return 1;
}
// If to file already exists and the iflag is set ... block move
if(iflag && file_exists(to)) {
if(!silent) write("Mv: " + to + " already exists.\n");
return 1; }
// Attempt to move the file to new location
if (!file_lock(from, F_LOCK)) {
if (!silent)
write("Mv: File \"" + from + "\" busy.\n");
return 0;
}
if (!file_lock(to, F_LOCK)) {
file_lock(from, F_UNLOCK);
if (!silent)
write("Mv: File \"" + to + "\" busy.\n");
return 0;
}
catch( rename(from, to) );
if(file_exists(from) || !file_exists(to)) {
if(!silent) write("Mv: Could not move " + from + " to " + to + "\n");
}
else if(!silent) write("Mv: " + from + " moved to " + to + "\n");
file_lock(to, F_UNLOCK);
file_lock(from, F_UNLOCK);
return 1; }
// This function returns the file path of a passed file.
static string get_path(string str, int dir_flag) {
mixed *tmp;
string path;
if(str == "/") return "";
else if(dir_flag) return str;
else if(directory_exists(str)) return str + "/";
tmp = explode(str, "/");
path = "/" + implode( tmp[0..sizeof(tmp)-2], "/") + "/";
if(path == "//") path = "";
return path; }
// This function returns the filename without the whole file path
static string get_file(string str) {
mixed *tmp;
tmp = explode(str, "/");
return tmp[sizeof(tmp)-1]; }
// This is the commands help function
string help() {
return(SYNTAX @ENDHELP
This command can be used for moving a file or directory to a new location.
By using wildcards, this command can move many files and directories,
matching the specified pattern, at the same time. Also, this command can
used for renaming a file or directory, where source is the old name, and
destination is the desired new name.
The following flags are recognized:
f - force overwriting files if they already exist (default; overrides 'i')
i - don't overwrite files if they already exist (historically "interactive")
r - "recursively" move the entire directory tree to the new location
s - silent "mv"; notifies only when operation has been completed
To move files to your present directory, simply use "." as the destination.
ENDHELP
);
}