cdesktopenv/cde/programs/dtfile/FileOp.c

3609 lines
112 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $TOG: FileOp.c /main/14 1999/12/09 13:06:21 mgreess $ */
/************************************<+>*************************************
****************************************************************************
*
* FILE: FileOp.c
*
* COMPONENT_NAME: Desktop
*
* DESCRIPTION: File processing functions.
*
* FUNCTIONS: ChangeIconName
* ChangeIconNameDT
* ChangeIconNameProcess
* ChangeIconPipeCB
* CreateFileFromBuffer
* DisplayDuplicateOpError
* DisplayErrorMessage
* FileMoveCopy
* FileMoveCopyDesktop
* FileMoveCopyProcess
* FileMoveCopyProcessDesktop
* FileOpError
* FileOpPipeCB
* GetTarget
* MakeFile
* MakeFilePipeCB
* MakeFileProcess
* MakeFilesFromBuffers
* MakeFilesFromBuffersDT
* PipeRead
* PipeReadString
* PipeWriteErrmsg
* PipeWriteString
* RemoveIconFromWorkspace
* ChangeWorkspaceIconLink
* SendModifyMsg
* _ChangeIconName
* _FileMoveCopy
* appendErrorMessage
* moveCopyLinkCancel
* moveCopyLinkOK
*
* (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
* (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
* (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
* (c) Copyright 1993, 1994, 1995 Novell, Inc.
*
****************************************************************************
************************************<+>*************************************/
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <time.h>
#include <utime.h>
#ifdef __osf__
#include <unistd.h>
#endif
#ifdef _AIX
#include <sys/select.h>
#endif
#if defined(_AIX)|| defined(hpux)
#include <sys/dir.h>
#else
#ifndef MAXNAMLEN
#define MAXNAMLEN 255
#endif
#endif
#include <Xm/XmP.h>
#include <Xm/Xm.h>
#include <Xm/MwmUtil.h>
#include <Xm/TextF.h>
#include <Xm/ScrollBar.h>
#include <X11/ShellP.h>
#include <X11/Shell.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#ifdef SHAPE
#include <X11/extensions/shape.h>
#endif
#include <Dt/Icon.h>
#include <Dt/IconP.h>
#include <Dt/IconFile.h>
#include <Dt/Action.h>
#include <Dt/Connect.h>
#include <Dt/Wsm.h>
#include <Dt/DtNlUtils.h>
#include <Dt/HourGlass.h>
#include <Dt/SharedProcs.h>
#include <Tt/tttk.h>
#include "Encaps.h"
#include "SharedProcs.h"
#include "FileMgr.h"
#include "Desktop.h"
#include "Main.h"
#include "Prefs.h"
#include "Common.h"
#include "Filter.h"
#include "Help.h"
#include "SharedMsgs.h"
#include "sharedFuncs.h"
/* Static Function declarations */
static Boolean CreateFileFromBuffer(
int pipe_s2m,
char *directory,
char *fully_qualified_name,
void *buffer,
int size);
static String appendErrorMessage(
String message,
String new,
String arg);
static void DisplayErrorMessage(
int pipe_s2m,
char *errMsg,
char *from,
char *dir);
static Boolean IsInParentDir(char *from,char *to);
/* the amount of time we wait for a file move/copy to complete */
/* @@@ should make this a resource */
#define FILE_MOVE_COPY_WAIT_TIME 2
/* types of messages sent through the pipe */
#define PIPEMSG_FILEOP_ERROR 1
#define PIPEMSG_EXIST_ERROR 2
#define PIPEMSG_OTHER_ERROR 3
#define PIPEMSG_CONFIRM 4
#define PIPEMSG_TARGET_TIME 5
#define PIPEMSG_FILE_MODIFIED 6
#define PIPEMSG_DONE 7
#define PIPEMSG_REPLACE_RENAME 8
#define PIPEMSG_REPLACE_RENAME_SAME 9
#define PIPEMSG_REPLACE_MERGE 10
#define PIPEMSG_MULTICOLLIDE 11
#define PIPEMSG_MULTICOLLIDE_SAME 12
#define PIPEMSG_MOVE_TO_SAME_DIR 13
/* the following messages are also defined & used in OverWrite.c */
#define PIPEMSG_CANCEL 101
#define PIPEMSG_PROCEED 102
#define PIPEMSG_MERGE 103
#define PIPEMSG_REPLACE_BUFFER 104
#define PIPEMSG_RENAME_BUFFER 105
#define PIPEMSG_MULTI_PROCEED 106
extern int G_dropx,G_dropy;
/* callback data for file move/copy/link */
typedef struct {
char *host;
char *directory;
char *app_man_dir;
BufferInfo bufferInfo;
int first_index;
Boolean time_sent;
Boolean operationStatus;
char *file;
} DirUpdate;
typedef struct
{
Boolean desktop;
FileMgrData *file_mgr_data;
FileMgrRec *file_mgr_rec;
FileViewData *file_view_data;
DesktopRec *desktopWindow;
int pipe_m2s; /* pipe main to slave */
int pipe_s2m; /* pipe slave to main */
int mode;
char *host;
char *directory;
int file_count;
DirUpdate *updates;
void (*finish_callback)();
XtPointer callback_data;
int child;
} FileOpCBData;
/* callback data for file rename */
typedef struct
{
Boolean desktop;
Widget w;
FileViewData *file_view_data;
DesktopRec *desktopWindow;
char *host_name;
char *directory_name;
char *old_name;
char *new_name;
int child;
} ChangeIconCBData;
/* callback data for create file/directory */
typedef struct
{
char *to_host;
char *to_dir;
char *to_file;
void (*finish_callback)();
XtPointer callback_data;
int child;
} MakeFileCBData;
static void
DisplayDuplicateOpError(FileOpCBData *cb_data,int index);
/*====================================================================
*
* Routine for sending data through a pipe
*
*==================================================================*/
/*--------------------------------------------------------------------
* PipeRead:
* Read data from the pipe
*------------------------------------------------------------------*/
int
PipeRead(
int fd,
void *buf,
int len)
{
static int whined_fd = -1;
int n = 0;
int rc;
while (n < len)
{
rc = read(fd, (char *)buf + n, len - n);
if (rc > 0)
n += rc;
else if (rc < 0 && errno == EINTR)
; /* try again */
else
{
if (rc == 0)
{
if (whined_fd != fd)
{
whined_fd = fd;
fprintf(stderr,
"PipeRead: broken pipe, ppid=%d pid=%d fd=%d\n",
getppid(), getpid(), fd);
}
}
else
{
perror("dtfile: read failed in PipeRead");
}
n = -1;
break;
}
}
return n;
}
/*--------------------------------------------------------------------
* PipeWriteString:
* write a string to the pipe
*------------------------------------------------------------------*/
int
PipeWriteString(
int fd,
char *s)
{
short len, sent = 0;
void (*oldPipe)();
oldPipe = (void (*)())signal(SIGPIPE, SIG_IGN);
if (s == NULL)
len = 0;
else
len = strlen(s);
if (write(fd, &len, sizeof(short)) < 0) {
return -1;
}
if (len > 0)
sent = write(fd, s, len);
signal(SIGPIPE, oldPipe);
return sent;
}
/*--------------------------------------------------------------------
* PipeReadString:
* read a string from the pipe
*------------------------------------------------------------------*/
char *
PipeReadString(
int fd)
{
short len;
char *s;
int n;
/* get the length */
if (PipeRead(fd, &len, sizeof(short)) != sizeof(short))
return NULL;
if (len == 0)
return NULL;
/* get the string */
s = (char *)XtMalloc(len + 1);
if (PipeRead(fd, s, len) != len)
{
XtFree(s);
return NULL;
}
s[len] = '\0';
return s;
}
/*--------------------------------------------------------------------
* PipeWriteErrmsg:
* write an error message to the pipe
*------------------------------------------------------------------*/
static int
PipeWriteErrmsg(
int fd,
int rc,
char *msg,
char *arg)
{
short pipe_msg = PIPEMSG_FILEOP_ERROR;
DPRINTF(("PipeWriteErrmsg: sending error %d \"%s\"\n", rc, msg));
write(fd, &pipe_msg, sizeof(short));
write(fd, &rc, sizeof(int));
PipeWriteString(fd, msg);
PipeWriteString(fd, arg);
return 0;
}
/*====================================================================
*
* FileMoveCopy
* Run a background process to move/copy/link files dropped
* on a dtfile window or icon.
*
*==================================================================*/
/*--------------------------------------------------------------------
* moveCopyLinkCancel:
* Cancel-button callback for overwrite confirmation dialog
*------------------------------------------------------------------*/
int filop_confirm_fd = -1; /* @@@ can't we pass this in client_data? */
static void
moveCopyLinkCancel(
Widget w,
XtPointer client_data,
XtPointer call_data )
{
const int rc = PIPEMSG_CANCEL;
/* close the dialog */
XtUnmanageChild((Widget)client_data);
XmUpdateDisplay((Widget)client_data);
XtDestroyWidget((Widget)client_data);
/* send return code through the pipe to the background proc */
write(filop_confirm_fd, &rc, sizeof(int));
filop_confirm_fd = -1;
}
/*--------------------------------------------------------------------
* moveCopyLinkOK:
* Ok-button callback for overwrite confirmation dialog
*------------------------------------------------------------------*/
static void
moveCopyLinkOK(
Widget w,
XtPointer client_data,
XtPointer call_data )
{
const int rc = PIPEMSG_PROCEED;
/* close the dialog */
XtUnmanageChild((Widget)client_data);
XmUpdateDisplay((Widget)client_data);
XtDestroyWidget((Widget)client_data);
/* send affirmative return code through the pipe to the background proc */
write(filop_confirm_fd, &rc, sizeof(int));
filop_confirm_fd = -1;
}
/*--------------------------------------------------------------------
* FileOpError
* Error handler for FileManip when called in the background process
*------------------------------------------------------------------*/
void
FileOpError(
Widget w,
char *message1,
char *message2 )
{
int pipe_fd = (int)w; /* @@@ Hack! @@@
In the background process we call FileManip with
the file descriptor for the pipe instead of a
widget id. We rely on the fact that FileManip
never uses the widget as a widget, but only
passes it to the error handler. */
/* write the error message to the pipe */
PipeWriteErrmsg(pipe_fd, -1, message1, message2);
}
/*--------------------------------------------------------------------
* SendModifyMsg:
* Send a message through the pipe that informs the main process
* that we are about to modify a directory or that a file has been
* modifed.
*------------------------------------------------------------------*/
static void
SendModifyMsg(
int pipe_fd,
int mode,
Boolean first,
char *to,
DirUpdate *updates,
int i,
char *target_file)
{
short pipe_msg;
char *dir_path;
long modify_time;
struct stat stat_buf;
int j;
/* if first operation on target dir, send timestamp */
if (first)
{
if (stat(to, &stat_buf) == 0)
{
modify_time = stat_buf.st_mtime;
pipe_msg = PIPEMSG_TARGET_TIME;
write(pipe_fd, &pipe_msg, sizeof(short));
write(pipe_fd, &modify_time, sizeof(long));
}
}
/* if first operation on source dir, get timestamp of source dir */
modify_time = 0;
j = updates[i].first_index;
if (mode == MOVE_FILE && !updates[j].time_sent)
{
Tt_status tt_status;
dir_path = ResolveLocalPathName(updates[i].host,
updates[i].directory,
NULL,
home_host_name,
&tt_status);
if (stat(dir_path, &stat_buf) == 0)
modify_time = stat_buf.st_mtime;
XtFree(dir_path);
updates[j].time_sent = True;
}
/* send the modify message */
pipe_msg = PIPEMSG_FILE_MODIFIED;
write(pipe_fd, &pipe_msg, sizeof(short));
write(pipe_fd, &i, sizeof(int));
write(pipe_fd, &modify_time, sizeof(long));
PipeWriteString(pipe_fd, target_file);
}
/*--------------------------------------------------------------------
* FileMoveCopyProcess:
* Main routine of the background process
*
* This routine has two basic modes of operation:
* It is given a list of source files and a target directory,
* and performs an operation on the source files. This mode
* is used for drag & drop operations where a user can
* select multiple source files and then drop them on a
* target directory to either move, copy, or copy-as-link
* the source files to the target directory. The source
* and target directories must be different.
* It is given a single source file and a target file. The
* target can be either a directory or a file. This mode
* is used for menu-intiated move, copy, or copy-as-link
* operations. The source and target directories can be
* the same.
* The source file(s) are given in updates; the destination is
* in host, dirctory, to_file. If to_file is NULL, the
* first mode (drag & drop) is assumed, otherwise assume
* menu-initiated mode.
*
*------------------------------------------------------------------*/
static int
FileMoveCopyProcess(
int pipe_s2m,
int pipe_m2s,
char *to_file,
char *directory,
char *host,
DirUpdate *updates,
int file_count,
int mode,
DesktopRec *desktopWindow)
{
char * target_dir, * from, * to;
int i, j, rc, result;
Boolean return_val = False;
Boolean isContainer;
long current;
char *tmpStr, *target_file;
struct stat stat_buf, from_stat_buf;
short pipe_msg;
int sameCount = 0;
int errorCount = 0;
int *sameIndex = NULL, *sameConfirmType = NULL;
Boolean first_op = True;
Tt_status tt_status;
char * renamed_file;
long modify_time;
String permissionErrors = NULL;
Boolean targetChecked = FALSE;
Boolean targetError = FALSE;
Boolean CopyError=FALSE,MoveError1=FALSE,MoveError2=FALSE;
char *CopyString=NULL,*MoveString1=NULL,*MoveString2=NULL;
Boolean Same;
/* Get the fully qualified destination path. */
target_dir = (char *)ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
if( TT_OK != tt_status )
{
char msg1[2*MAX_PATH];
#ifdef sun
sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
directory, host, host);
#else
sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
directory, host, host);
#endif
PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
pipe_msg = PIPEMSG_FILEOP_ERROR;
rc = -1;
write(pipe_s2m, &pipe_msg, sizeof(short));
write(pipe_s2m, &rc, sizeof(int));
return rc;
}
DtEliminateDots(target_dir);
for (i = 0; i < file_count; i++)
{
Same = False;
/* get full name of the source file, if just */
/* dealing with regular files */
if (mode != MAKE_BUFFER)
{
from = ResolveLocalPathName(updates[i].host,
updates[i].directory,
updates[i].file,
home_host_name,
&tt_status);
if (from == NULL)
{
char msg1[2*MAX_PATH];
#ifdef sun
sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
updates[i].directory, updates[i].host, updates[i].host);
#else
sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
updates[i].directory, updates[i].host, updates[i].host);
#endif
PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
continue;
}
/* do some extra error checking if a target filename is specified */
/* this is meant for the case of a menu-initiated operation */
if (to_file != NULL)
{
/* Verify that the target directory already exists */
if ( (stat(target_dir, &stat_buf) != 0) ||
(! S_ISDIR(stat_buf.st_mode) ) )
{
char *msg;
msg = XtNewString(
GETMESSAGE(11,41,"The folder\n%s\ndoes not exist."));
PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
errorCount++;
XtFree(msg);
XtFree(from);
continue;
}
}
/* check for a drop of a directory onto itself */
if (updates[i].app_man_dir)
{
char *temp_dir = XtNewString(target_dir);
temp_dir = _DtResolveAppManPath(temp_dir, updates[i].app_man_dir);
if (mode == MOVE_FILE && strcmp(temp_dir, from) == 0)
{
char *msg;
msg = XtNewString(
GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
PipeWriteErrmsg( pipe_s2m, -1, msg, temp_dir );
errorCount++;
XtFree(msg);
XtFree(from);
XtFree(temp_dir);
continue;
}
XtFree(temp_dir);
}
else if (mode == MOVE_FILE && strcmp(target_dir, from) == 0)
{
char *msg;
msg = XtNewString(
GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
errorCount++;
XtFree(msg);
XtFree(from);
continue;
}
else if (mode == MOVE_FILE && stat(from, &stat_buf) == 0 &&
S_ISDIR(stat_buf.st_mode) && DirectoryBusy(from))
{
char *msg;
msg = XtNewString( GETMESSAGE(11,30, "Cannot move or rename the folder %s.\nAll File Manager views displayed for a folder or its sub-folders\nmust be closed before a folder can be moved or renamed."));
PipeWriteErrmsg( pipe_s2m, -1, msg, from );
errorCount++;
XtFree(msg);
XtFree(from);
continue;
}
} /* end if */
/* for copy operations, check for read permission on the source file */
/* the error message is appended to a list and dealt with later */
/* the current file is not processed */
if (mode == COPY_FILE)
if (CheckAccess(from,R_OK) == -1)
{
struct stat sbuf;
char *tmpStr;
/* 'errno' is not giving correct results like 'ENOENT' in order to
use it here, may be because of the other system calls in
CheckAccess() */
if (stat(from, &sbuf) < 0)
tmpStr = (GETMESSAGE(28,13,"Object:\n\n %s\n\n does not exist in the file system"));
else
tmpStr = GetSharedMessage(CANT_READ_ERROR);
permissionErrors = appendErrorMessage(permissionErrors, tmpStr, from);
errorCount++;
continue;
}
if (to_file == NULL)
{
if (strcmp(target_dir, "/") == 0)
{
target_file = (char *)XtMalloc(strlen(target_dir) +
strlen(updates[i].file) + 1);
sprintf(target_file, "%s%s", target_dir, updates[i].file);
}
else
{
target_file = (char *)XtMalloc(strlen(target_dir) +
strlen(updates[i].file) + 2);
sprintf(target_file, "%s/%s", target_dir, updates[i].file);
}
}
else
{
if (strcmp(target_dir, "/") == 0)
{
target_file = (char *)XtMalloc(strlen(target_dir) +
strlen(to_file) + 1);
sprintf(target_file, "%s%s", target_dir, to_file);
}
else
{
target_file = (char *)XtMalloc(strlen(target_dir) +
strlen(to_file) + 2);
sprintf(target_file, "%s/%s", target_dir, to_file);
}
}
if (updates[i].app_man_dir)
target_file = _DtResolveAppManPath(target_file,
updates[i].app_man_dir);
/* check if source and target files are the same.
* if they are the same, set a flag noting that they are. If the
* the operation is a move, it doesn't make any sense to move it, so
* send back a MOVE_TO_SAME_DIR msg.
*/
if ((mode != MAKE_BUFFER) && (strcmp(target_file, from) == 0))
{
if (mode == MOVE_FILE && stat(target_file, &stat_buf) == 0)
{
if(S_ISDIR(stat_buf.st_mode))
{
pipe_msg = PIPEMSG_MOVE_TO_SAME_DIR;
write(pipe_s2m, &pipe_msg, sizeof(short));
write(pipe_s2m, &i, sizeof(int));
errorCount++;
continue;
}
}
Same = True;
}
/* for copy operations, check for write permission on the target */
/* directory */
/* for move operations, check for write permission on the source and */
/* target directories */
/* the error message is appended to a list and dealt with later */
/* the current file is not processed */
if (mode == COPY_FILE)
{
if (CheckAccess(target_dir,W_OK) == -1)
{
CopyError = TRUE;
errorCount++;
if(CopyString == NULL)
CopyString = XtNewString(from);
else
{
CopyString = (char *) XtRealloc(CopyString,strlen(CopyString)+
strlen(from)+2);
strcat(CopyString,"\n");
strcat(CopyString,from);
}
continue;
}
}
else if (mode == MOVE_FILE)
{
Boolean error = FALSE;
if (targetChecked || CheckAccess(target_dir,W_OK) == -1)
{
MoveError1 = TRUE;
if(MoveString1 == NULL)
MoveString1 = XtNewString(from);
else
{
MoveString1=(char *)XtRealloc(MoveString1,strlen(MoveString1)+
strlen(from)+2);
strcat(MoveString1,"\n");
strcat(MoveString1,from);
}
error = targetError = TRUE;
targetChecked = TRUE;
}
if (CheckAccess(_DtPName(from),W_OK) == -1)
{
MoveError2 = TRUE;
if(MoveString2 == NULL)
MoveString2 = XtNewString(from);
else
{
MoveString2 = (char *)XtRealloc(MoveString2,strlen(MoveString2)+
strlen(from)+2);
strcat(MoveString2,"\n");
strcat(MoveString2,from);
}
error = TRUE;
}
if (error || targetError)
{
errorCount++;
continue;
}
}
/* check if target file already exists */
if (stat(target_file, &stat_buf) == 0)
{
/* target file already exists: remember and deal with it later */
if(mode == MOVE_FILE && S_ISDIR(stat_buf.st_mode)
&& DirectoryBusy(target_file))
{
char *msg;
msg = XtNewString( GETMESSAGE(11,30, "Cannot move or rename the folder %s.\nAll File Manager views displayed for a folder or its sub-folders\nmust be closed before a folder can be moved or renamed."));
PipeWriteErrmsg( pipe_s2m, -1, msg, target_file );
errorCount++;
XtFree(msg);
XtFree(target_file);
continue;
}
if (sameIndex == NULL)
{
sameIndex = (int *)XtMalloc(file_count*sizeof(int));
sameConfirmType = (int *)XtMalloc(file_count*sizeof(int));
}
sameIndex[sameCount] = i;
/* determine how to set the pipe message */
if (mode == MAKE_BUFFER)
{
sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
}
else
{
stat(from, &from_stat_buf);
if ( S_ISDIR(from_stat_buf.st_mode) &&
S_ISDIR(stat_buf.st_mode) &&
mode == COPY_FILE )
{
/* if its a directory and there already is a directory of the
* same name the user may want to merge the directories into
* one directory. But if the directory to be copied is being
* copied into the same directory it came from, it doesn't make
* sense to merge. Set up message to REPLACE_RENAME_SAME
* indicating it is being copied from and to the same directory
*/
if(Same)
sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
else
sameConfirmType[sameCount] = PIPEMSG_REPLACE_MERGE;
}
else
{
/* If the copy/move/link is to the same directory, set up a
* different case then when the op is happening from different
* directories.
*/
if(Same)
sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
else
sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
}
} /* endif mode != MAKE_BUFFER */
sameCount++;
if (mode != MAKE_BUFFER)
XtFree ((char *) from);
XtFree ((char *) target_file);
continue;
} /* endif targetfile already exists */
if ((isContainer = (to_file == NULL)))
to = target_dir;
else
to = target_file;
/*
* Note: it is important that SendModifyMsg is called before any
* changes are made to either the source or target directory.
* This is because SendModifyMsg is supposed to obtain and send
* the time stamp of the directories BEFORE any operation. If
* the wrong timestamp is sent, the window will be updated and
* redrawn twice instead of just once.
*/
SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, i,
updates[i].file);
first_op = False;
if (mode == MAKE_BUFFER)
{
/* Call CreateFileFromBuffer */
return_val = CreateFileFromBuffer(pipe_s2m, to,
target_file,
updates[i].bufferInfo.buf_ptr,
updates[i].bufferInfo.size);
}
else
{
if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
return_val = FileManip((Widget)pipe_s2m, mode, from, to,
isContainer,
FileOpError, True, DESKTOP);
else
return_val = FileManip((Widget)pipe_s2m, mode, from, to,
isContainer,
FileOpError, True, NOT_DESKTOP);
XtFree( (char *) from );
}
XtFree ((char *) target_file);
} /* end for loop */
if(CopyError == TRUE)
{
String errMsg;
errMsg = GETMESSAGE(11,48,
"Cannot copy the following objects to folder \"%s\"\n\n%s\n\nThe most likely cause is that you do not have\nwrite permission for the target folder");
DisplayErrorMessage(pipe_s2m,errMsg,CopyString,target_dir);
CopyError = FALSE;
permissionErrors = NULL;
XtFree(CopyString);
CopyString = NULL;
}
if(MoveError1 == TRUE)
{
String errMsg;
errMsg = GETMESSAGE(11,49,
"Cannot move the following objects to folder \"%s\"\n\n%s\n\nThe most likely cause is that you do not have\nwrite permission for the target folder");
DisplayErrorMessage(pipe_s2m,errMsg,MoveString1,target_dir);
MoveError1 = FALSE;
permissionErrors = NULL;
XtFree(MoveString1);
MoveString2 = NULL;
}
if(MoveError2 == TRUE)
{
String errMsg;
errMsg = GETMESSAGE(11,50,
"Cannot move the following objects to folder \"%s\"\n\n%s\n\nThe most likely cause is that you do not have\npermission to move source object");
DisplayErrorMessage(pipe_s2m,errMsg,MoveString2,target_dir);
MoveError2 = FALSE;
permissionErrors = NULL;
XtFree(MoveString2);
MoveString2 = NULL;
}
/* If there were any permissions errors, show the error message */
if (permissionErrors != NULL)
{
PipeWriteErrmsg(pipe_s2m, -1, permissionErrors, NULL);
XtFree(permissionErrors);
}
/*
* Now deal with with the cases where we found that the target file
* already exists.
*/
if (sameCount != 0)
{
/*
* @@@ Note: The code below for sending a target-time pipe message
* at this point shouldn't really be necessary.
* The problem is that the target directory time stamp MUST be
* obtained BEFORE any changes are made to the directory;
* otherwise, the window will be updated and redrawn twice instead
* of just once. Unfortunately, currently, if the user chooses to
* replace or rename the existing file, the rename or delete
* operation is done in the main process (inside the
* replace_rename_ok_callback in Overwrite.c), instead of here in
* the child process where it belongs (the main process shouldn't
* do any file system operations because they could block for a
* long time on a slow server). If and when overwrite dialog code
* is fixed, the code below can be deleted; the target-time
* message will then be sent by the call to SendModifyMsg further
* below after the call to PipeRead.
*/
if (first_op)
{
if (stat(target_dir, &stat_buf) == 0)
{
modify_time = stat_buf.st_mtime;
pipe_msg = PIPEMSG_TARGET_TIME;
write(pipe_s2m, &pipe_msg, sizeof(short));
write(pipe_s2m, &modify_time, sizeof(long));
}
first_op = False;
}
/* send message to main process to display dialog (and possibly remove/rename files) */
if (file_count == 1)
{
if (to_file == NULL) /* note target_file here is only file name, above it is full path */
target_file = updates[sameIndex[0]].file;
else
target_file = to_file;
pipe_msg = sameConfirmType[0];
DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
write(pipe_s2m, &pipe_msg, sizeof(short));
DPRINTF(("FileMoveCopyProcess: sending: mode %d directory \"%s\" file \"%s\" \n",
mode, directory, target_file));
write(pipe_s2m, &mode, sizeof(int));
PipeWriteString(pipe_s2m, directory);
PipeWriteString(pipe_s2m, target_file);
}
else
{
int processCount=file_count-errorCount;
/* If the copy/move/link is to the same directory, set up a
* different case then when the op is happening from different
* directories.
*/
if(Same)
pipe_msg = PIPEMSG_MULTICOLLIDE_SAME;
else
pipe_msg = PIPEMSG_MULTICOLLIDE;
DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
write(pipe_s2m, &pipe_msg, sizeof(short));
DPRINTF(("FileMoveCopyProcess: sending: mode %d processCount %d sameCount %d directory \"%s\"\n",
mode, processCount, sameCount, directory));
write(pipe_s2m, &mode, sizeof(int));
write(pipe_s2m, &processCount, sizeof(int));
write(pipe_s2m, &sameCount, sizeof(int));
PipeWriteString(pipe_s2m, directory);
DPRINTF(("FileMoveCopyProcess: sending %d filename strings\n", sameCount));
for (i = 0; i < sameCount; i++)
PipeWriteString(pipe_s2m, updates[sameIndex[i]].file);
}
/* wait for reply from main process */
rc = -1;
PipeRead(pipe_m2s, &rc, sizeof(int));
DPRINTF(("FileMoveCopyProcess: woke up after confirm, rc %d\n", rc));
if (rc != PIPEMSG_CANCEL)
{
/* affirmative reply: do the operation */
for(i = 0; i < sameCount; i++)
{
j = sameIndex[i];
if (rc != PIPEMSG_RENAME_BUFFER)
{
SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, j,
updates[j].file);
first_op = FALSE;
}
if (rc == PIPEMSG_MULTI_PROCEED)
{
int opvalue;
PipeRead(pipe_m2s, &opvalue, sizeof(int));
if(opvalue != 0)
continue;
}
if (mode != MAKE_BUFFER)
{
from = ResolveLocalPathName( updates[j].host,
updates[j].directory,
updates[j].file,
home_host_name,
&tt_status);
if( TT_OK != tt_status )
{
char msg1[2*MAX_PATH];
#ifdef sun
sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
updates[j].directory, updates[j].host,
updates[j].host);
#else
sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
updates[j].directory, updates[j].host,
updates[j].host);
#endif
PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
continue;
}
} /* endif */
if ( (isContainer = (to_file == NULL)) )
{
to = target_dir;
}
else
{
to = (char *)XtMalloc(strlen(target_dir) + strlen(to_file) + 2);
sprintf(to, "%s/%s", target_dir, to_file);
}
/* check the return code for type of message and */
/* perform the appropriate action */
switch (rc)
{
case PIPEMSG_MERGE:
if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
return_val = FileManip((Widget)pipe_s2m, MERGE_DIR, from,
to, isContainer,
FileOpError, True, DESKTOP);
else
return_val = FileManip((Widget)pipe_s2m, MERGE_DIR, from,
to, isContainer,
FileOpError, True, NOT_DESKTOP);
break;
case PIPEMSG_REPLACE_BUFFER:
target_file = (char *)XtMalloc(strlen(to) + strlen(updates[j].file)
+ 2);
sprintf(target_file, "%s/%s", to, updates[j].file);
DPRINTF (("file is %s",updates[j].file));
return_val = CreateFileFromBuffer(pipe_s2m,
to,
target_file,
updates[j].bufferInfo.buf_ptr,
updates[j].bufferInfo.size);
XtFree((char *)target_file);
target_file = NULL;
break;
case PIPEMSG_RENAME_BUFFER:
renamed_file = PipeReadString(pipe_m2s);
SendModifyMsg(pipe_s2m, mode, first_op, to, updates, j, renamed_file);
target_file = (char *)XtMalloc(strlen(to) + strlen(renamed_file)
+ 2);
sprintf(target_file, "%s/%s", to, renamed_file);
DPRINTF(("file is %s",renamed_file));
return_val = CreateFileFromBuffer(pipe_s2m,
to,
target_file,
updates[j].bufferInfo.buf_ptr,
updates[j].bufferInfo.size);
XtFree((char *) target_file);
target_file = NULL;
break;
default:
if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
return_val = FileManip((Widget)pipe_s2m, mode, from, to,
isContainer,FileOpError, True,
DESKTOP);
else
{
/* if the operation (move/copy/link) is happening from
* and to the same folder, we want to create a new name
* for the object for which the operation is happening
* on.
*/
if(Same)
{
char path[MAX_PATH], newDir[MAX_PATH],
newFile[MAX_PATH];
char *toFile;
strcpy(path, from);
generate_NewPath(path,path);
split_path(path, newDir, newFile);
toFile = (char *)XtMalloc(strlen(newDir) +
strlen(newFile) + 3);
strcpy(toFile, newDir);
strcat(toFile, "/");
strcat(toFile, newFile);
return_val = FileManip((Widget)pipe_s2m, mode, from,
toFile, False, FileOpError,
True, NOT_DESKTOP);
XtFree(path);
XtFree(toFile);
}
else
return_val = FileManip((Widget)pipe_s2m, mode, from,
to, isContainer, FileOpError,
True, NOT_DESKTOP);
}
} /* endswitch */
if (to_file != NULL)
{
XtFree ((char *) to);
to = NULL;
}
}/* end for */
}/*end if rc != PIPEMSG_CANCEL*/
/* free sameData */
XtFree((char *)sameIndex);
sameIndex = NULL;
XtFree((char *)sameConfirmType);
sameConfirmType = NULL;
sameCount = 0;
} /* endif sameCount != 0 */
pipe_msg = PIPEMSG_DONE;
if (rc != PIPEMSG_CANCEL)
rc = return_val? 0: -1;
else
rc = 0;
write(pipe_s2m, &pipe_msg, sizeof(short));
write(pipe_s2m, &rc, sizeof(int));
XtFree ((char *) target_dir);
target_dir = NULL;
return rc;
}
/*--------------------------------------------------------------------
* FileMoveCopyProcessDesktop:
* Main routine of the background process that handles files
* dropped in desktop icons.
*------------------------------------------------------------------*/
static int
FileMoveCopyProcessDesktop(
int pipe_s2m,
int pipe_m2s,
char *directory,
char *host,
DirUpdate *updates,
int file_count,
int mode,
DesktopRec *desktopWindow)
{
char * to, *from;
int i, rc;
Boolean first_op = True;
Boolean return_val = False;
short pipe_msg;
Tt_status tt_status;
/* Get the fully qualified destination path. */
to = ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
if( TT_OK != tt_status )
{
char msg1[2*MAX_PATH];
#ifdef sun
sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
directory, host, host);
#else
sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
directory, host, host);
#endif
PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
pipe_msg = PIPEMSG_FILEOP_ERROR;
rc = -1;
write(pipe_s2m, &pipe_msg, sizeof(short));
write(pipe_s2m, &rc, sizeof(int));
return rc;
}
DtEliminateDots(to);
for (i = 0; i < file_count; i++)
{
/* get full name of the source file, if just */
/* dealing with regular files */
if (mode != MAKE_BUFFER)
{
from = ResolveLocalPathName(updates[i].host,
updates[i].directory,
updates[i].file,
home_host_name,
&tt_status);
if (from == NULL)
{
char msg[2*MAX_PATH];
#ifdef sun
sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
updates[i].directory, updates[i].host, updates[i].host);
#else
sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
updates[i].directory, updates[i].host, updates[i].host);
#endif
PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
}
else if (strcmp(to, from) == 0)
{
char msg[2*MAX_PATH];
sprintf(msg,GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"),to);
PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
XtFree ((char *) from);
from = NULL;
}
} /* end if dealing with regular files */
SendModifyMsg(pipe_s2m, mode, first_op, to, updates, i, updates[i].file);
return_val = True;
if (mode == MAKE_BUFFER)
{
char *target_file;
if (strcmp(to, "/") == 0)
{
target_file = (char *) XtMalloc(strlen(to) +
strlen(updates[i].file) + 1);
sprintf(target_file, "%s%s", to, updates[i].file);
}
else
{
target_file = (char *) XtMalloc(strlen(to) +
strlen(updates[i].file) + 2);
sprintf(target_file, "%s/%s", to, updates[i].file);
}
return_val = CreateFileFromBuffer(pipe_s2m,
to,
target_file,
updates[i].bufferInfo.buf_ptr,
updates[i].bufferInfo.size);
}
else
{
return_val = FileManip((Widget)pipe_s2m, mode, from, to, TRUE,
FileOpError, True, DESKTOP);
XtFree (from);
from = NULL;
}
}
pipe_msg = PIPEMSG_DONE;
rc = return_val? 0: -1;
write(pipe_s2m, &pipe_msg, sizeof(short));
write(pipe_s2m, &rc, sizeof(int));
XtFree ((char *) to);
return rc;
}
static void
RemoveIconFromWorkspace( char * iconName,
char * targetDir )
{
DesktopRec *desktopWin;
int i;
char fileName[MAX_PATH];
for(i = 0; i < desktop_data->numIconsUsed; i++)
{
desktopWin = desktop_data->desktopWindows[i];
if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
sprintf( fileName, "/%s", desktopWin->file_name );
else
sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
if( strcmp( fileName, iconName ) == 0 )
{
Window rootWindow;
Atom pCurrent;
Screen *currentScreen;
int screen;
char *workspace_name;
screen = XDefaultScreen(XtDisplay(desktopWin->shell));
currentScreen =
XScreenOfDisplay(XtDisplay(desktopWin->shell), screen);
rootWindow = RootWindowOfScreen(currentScreen);
if(DtWsmGetCurrentWorkspace(XtDisplay(desktopWin->shell),
rootWindow, &pCurrent) == Success)
workspace_name =
XGetAtomName (XtDisplay(desktopWin->shell), pCurrent);
else
workspace_name = XtNewString("One");
if( strcmp( workspace_name, desktopWin->workspace_name ) == 0 )
{
RemoveDT( desktopWin->shell, (XtPointer) desktopWin,
(XtPointer)NULL );
}
else
{
XtFree( desktopWin->dir_linked_to );
desktopWin->dir_linked_to = XtNewString( targetDir );
}
XtFree(workspace_name);
}
}
}
static void
ChangeWorkspaceIconLink( FileMgrData *fmd,
char * iconName,
char * targetDir,
char * iconPdir )
{
DesktopRec *desktopWin;
char *dirp = NULL;
int i;
char fileName[MAX_PATH];
for(i = 0; i < desktop_data->numIconsUsed; i++)
{
desktopWin = desktop_data->desktopWindows[i];
if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
sprintf( fileName, "/%s", desktopWin->file_name );
else
sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
DtEliminateDots(fileName);
if( strcmp( fileName, iconName ) == 0 )
dirp = XtNewString(targetDir);
else if(IsInParentDir(iconName,desktopWin->dir_linked_to))
{
int index = strlen(iconPdir);
char *tptr = desktopWin->dir_linked_to;
dirp = XtCalloc( 1, strlen(targetDir)+ strlen(&tptr[index])+1);
sprintf(dirp,"%s%s",targetDir,&tptr[index]);
}
if(dirp)
{
FileViewData *file_view_data;
DirectorySet *directory_set;
FileMgrData *file_mgr_data;
Tt_status tt_status;
char * full_dir_name;
file_view_data = desktopWin->file_view_data;
directory_set = (DirectorySet *)file_view_data->directory_set;
file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
if(file_mgr_data)
fmd = file_mgr_data;
FreeFileData( file_view_data->file_data, True );
file_view_data->file_data = NULL;
XtFree( desktopWin->dir_linked_to );
desktopWin->dir_linked_to = XtNewString( dirp );
DtEliminateDots(desktopWin->dir_linked_to);
if(fmd)
{
if (fmd->restricted_directory == NULL)
desktopWin->restricted_directory = NULL;
else
desktopWin->restricted_directory =
XtNewString(fmd->restricted_directory);
if (fmd->helpVol == NULL)
desktopWin->helpVol = NULL;
else
desktopWin->helpVol = XtNewString(fmd->helpVol);
desktopWin->helpVol = XtNewString( fmd->helpVol );
desktopWin->view = fmd->view;
desktopWin->order = fmd->order;
desktopWin->direction = fmd->direction;
desktopWin->positionEnabled = fmd->positionEnabled;
desktopWin->toolbox = fmd->toolbox;
}
full_dir_name = ResolveLocalPathName(desktopWin->host,
dirp,
NULL,
home_host_name,
&tt_status);
if( TT_OK == tt_status )
{
FileData2 file_data2;
int n;
Boolean IsToolBox;
DtEliminateDots (full_dir_name);
if ( fmd )
IsToolBox = fmd->toolbox;
else
IsToolBox = False;
if (strcmp(desktopWin->file_name, ".") == 0)
ReadFileData2(&file_data2, full_dir_name, NULL, IsToolBox);
else
ReadFileData2(&file_data2, full_dir_name, desktopWin->file_name,
IsToolBox);
file_view_data->file_data = FileData2toFileData(&file_data2, &n);
XtFree(full_dir_name);
full_dir_name = NULL;
}
((DirectorySet *)file_view_data->directory_set)->name =
XtNewString(dirp);
SaveDesktopInfo(NORMAL_RESTORE);
XtFree(dirp);
dirp = NULL;
}
}
}
/*--------------------------------------------------------------------
* FileOpPipeCB
* Read and process data sent through the pipe.
*------------------------------------------------------------------*/
static void
FileOpPipeCB(
XtPointer client_data,
int *fd,
XtInputId *id)
{
FileOpCBData *cb_data = (FileOpCBData *)client_data;
short pipe_msg;
int i, n, rc;
char *title, *err_msg, *err_arg;
char *directory, *file, *target_file;
long modify_time;
Boolean done;
int mode;
int nSelected, nCollisions;
String *fileList;
static int status = 0;
static ActionAreaItem replace_rename_actionItems[] = {
{"Ok", 9, 27, NULL, NULL}, /* changed later based on mode */
{"Cancel", 9, 28, replace_rename_cancel_callback, NULL},
{"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_REN},
};
ActionAreaDefn replace_renameActions = {
XtNumber(replace_rename_actionItems),
1, /* Cancel is default action */
replace_rename_actionItems
};
static ActionAreaItem replace_merge_actionItems[] = {
{"Ok", 9, 27, replace_merge_ok_callback, NULL},
{"Cancel", 9, 28, replace_merge_cancel_callback, NULL}, /* changed below depending on mode */
{"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_MRG},
};
ActionAreaDefn replace_mergeActions = {
XtNumber(replace_merge_actionItems),
1, /* Cancel is default action */
replace_merge_actionItems
};
static ActionAreaItem multicollide_actionItems[] = {
{"Ok", 9, 27, NULL, NULL}, /* changed later based on Mode */
{"Cancel", 9, 28, multicollide_cancel_callback, NULL}, /* changed below depending on mode */
{"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_MULTI},
};
ActionAreaDefn multicollideActions = {
XtNumber(multicollide_actionItems),
1, /* Cancel is default action */
multicollide_actionItems
};
/* Initialize Action Area structures based on mode */
/* Set the appropriate callback routines */
mode = cb_data->mode;
switch (mode)
{
case MAKE_BUFFER:
replace_rename_actionItems[0].callback =
buffer_replace_rename_ok_callback;
multicollide_actionItems[0].callback =
buffer_multicollide_ok_callback;
break;
default:
replace_rename_actionItems[0].callback =
replace_rename_ok_callback;
multicollide_actionItems[0].callback =
multicollide_ok_callback;
} /* endswitch */
/* read the next msg from the pipe */
pipe_msg = -1;
n = PipeRead(*fd, &pipe_msg, sizeof(short));
DPRINTF(("FileOpPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
done = False;
switch (pipe_msg)
{
case PIPEMSG_FILEOP_ERROR:
PipeRead(*fd, &rc, sizeof(int));
err_msg = PipeReadString(*fd);
err_arg = PipeReadString(*fd);
if (cb_data->desktop)
FileOperationError(cb_data->file_view_data->widget,
err_msg, err_arg);
else
{
/* routine can be called with a NULL file_mgr_rec, use the
* top level widget if this is the case.
*/
if(cb_data->file_mgr_rec)
FileOperationError(cb_data->file_mgr_rec->file_window,
err_msg, err_arg);
else
FileOperationError(toplevel, err_msg, err_arg);
}
XtFree(err_msg);
XtFree(err_arg);
if(cb_data->callback_data)
{
RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
}
status = PIPEMSG_FILEOP_ERROR;
break;
case PIPEMSG_CONFIRM:
err_msg = PipeReadString(*fd);
title = XtNewString(GETMESSAGE(9,11, "File Manager - Move/Copy/Link Warning"));
filop_confirm_fd = cb_data->pipe_m2s;
_DtMessageDialog(toplevel, title, err_msg, NULL, TRUE,
moveCopyLinkCancel, moveCopyLinkOK, NULL,
HelpRequestCB, False, QUESTION_DIALOG);
XtFree(err_msg);
XtFree(title);
break;
case PIPEMSG_REPLACE_RENAME_SAME:
/* filename collision: display replace/rename dialog */
PipeRead(*fd, &mode, sizeof(int));
directory = PipeReadString(*fd);
file = PipeReadString(*fd);
/* routine can be called with a NULL file_mgr_rec, use the
* top level widget if this is the case.
*/
/* the object is copying/linking itself to the same folder. Want
* to indicate the to the ok dialog and the building of the replace
* name dialog.
*/
replace_rename_actionItems[0].data = (XtPointer)True;
if(cb_data->file_mgr_rec)
create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
mode, directory, file,
cb_data->pipe_m2s,
replace_renameActions, True);
else
create_replace_rename_dialog(toplevel,
mode, directory, file,
cb_data->pipe_m2s,
replace_renameActions, True);
XtFree(directory);
XtFree(file);
break;
case PIPEMSG_REPLACE_RENAME:
/* filename collision: display replace/rename dialog */
PipeRead(*fd, &mode, sizeof(int));
directory = PipeReadString(*fd);
file = PipeReadString(*fd);
/* routine can be called with a NULL file_mgr_rec, use the
* top level widget if this is the case.
*/
replace_rename_actionItems[0].data = (XtPointer)NULL;
if(cb_data->file_mgr_rec)
create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
mode, directory, file,
cb_data->pipe_m2s,
replace_renameActions, False);
else
create_replace_rename_dialog(toplevel,
mode, directory, file,
cb_data->pipe_m2s,
replace_renameActions, False);
XtFree(directory);
XtFree(file);
break;
case PIPEMSG_REPLACE_MERGE:
/* filename collision: display replace/merge dialog */
PipeRead(*fd, &mode, sizeof(int));
directory = PipeReadString(*fd);
file = PipeReadString(*fd);
/* routine can be called with a NULL file_mgr_rec, use the
* top level widget if this is the case.
*/
if(cb_data->file_mgr_rec)
create_replace_merge_dialog(cb_data->file_mgr_rec->shell,
mode, directory, file,
cb_data->pipe_m2s,
replace_mergeActions);
else
create_replace_merge_dialog(toplevel,
mode, directory, file,
cb_data->pipe_m2s,
replace_mergeActions);
XtFree(directory);
XtFree(file);
break;
case PIPEMSG_MULTICOLLIDE_SAME:
/* filename collision: display multicollide dialog */
PipeRead(*fd, &mode, sizeof(int));
PipeRead(*fd, &nSelected, sizeof(int));
PipeRead(*fd, &nCollisions, sizeof(int));
directory = PipeReadString(*fd);
file = XtMalloc( MAX_PATH );
fileList = (String *) XtMalloc(nCollisions * sizeof(String)); /* de- allocated in dialog's callback functions */
for (i = 0; i < nCollisions; i++)
{
fileList[i] = PipeReadString(*fd);
}
/* routine can be called with a NULL file_mgr_rec, use the
* top level widget if this is the case.
*/
/* the object is copying/linking itself to the same folder. Want
* to indicate the to the ok dialog and the building of the replace
* name dialog.
*/
multicollide_actionItems[0].data = (XtPointer)True;
if(cb_data->file_mgr_rec)
create_multicollide_dialog(cb_data->file_mgr_rec->shell,
mode, nSelected, nCollisions,
directory, fileList,
cb_data->pipe_m2s,
multicollideActions, True);
else
create_multicollide_dialog(toplevel,
mode, nSelected, nCollisions,
directory, fileList,
cb_data->pipe_m2s,
multicollideActions, True);
XtFree(directory);
break;
case PIPEMSG_MULTICOLLIDE:
/* filename collision: display multicollide dialog */
PipeRead(*fd, &mode, sizeof(int));
PipeRead(*fd, &nSelected, sizeof(int));
PipeRead(*fd, &nCollisions, sizeof(int));
directory = PipeReadString(*fd);
file = XtMalloc( MAX_PATH );
fileList = (String *) XtMalloc(nCollisions * sizeof(String)); /* de-allocated in dialog's callback functions */
for (i = 0; i < nCollisions; i++)
{
fileList[i] = PipeReadString(*fd);
}
/* routine can be called with a NULL file_mgr_rec, use the
* top level widget if this is the case.
*/
multicollide_actionItems[0].data = (XtPointer)NULL;
if(cb_data->file_mgr_rec)
create_multicollide_dialog(cb_data->file_mgr_rec->shell,
mode, nSelected, nCollisions,
directory, fileList,
cb_data->pipe_m2s,
multicollideActions, False);
else
create_multicollide_dialog(toplevel,
mode, nSelected, nCollisions,
directory, fileList,
cb_data->pipe_m2s,
multicollideActions, False);
XtFree(directory);
break;
case PIPEMSG_TARGET_TIME:
/* get the modify time and update the directory cache */
PipeRead(*fd, &modify_time, sizeof(long));
DirectoryModifyTime(cb_data->host, cb_data->directory, modify_time);
break;
case PIPEMSG_MOVE_TO_SAME_DIR:
/* get the update index */
PipeRead(*fd, &i, sizeof(int));
cb_data->updates[i].operationStatus = True;
DisplayDuplicateOpError((void *) cb_data,i);
status = PIPEMSG_MOVE_TO_SAME_DIR;
if(cb_data->callback_data)
{
RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
}
break;
case PIPEMSG_FILE_MODIFIED:
/* get the update index and modify time */
PipeRead(*fd, &i, sizeof(int));
PipeRead(*fd, &modify_time, sizeof(long));
target_file = PipeReadString(*fd);
DPRINTF (("PIPEMSG_FILE_MODIFIED %s\n", target_file));
/* mark the file updated in the cached target directory */
DirectoryFileModified(cb_data->host, cb_data->directory,
target_file);
if (cb_data->mode == MOVE_FILE)
{
/* mark the file updated in the cached source directory */
if (modify_time != 0)
DirectoryModifyTime(cb_data->updates[i].host,
cb_data->updates[i].directory,
modify_time);
DirectoryFileModified(cb_data->updates[i].host,
cb_data->updates[i].directory,
cb_data->updates[i].file);
}
cb_data->updates[i].operationStatus = True;
XtFree(target_file); target_file = NULL;
break;
case PIPEMSG_DONE:
PipeRead(*fd, &rc, sizeof(int));
done = True;
break;
default:
fprintf(stderr, "Internal error in FileOpPipeCB: bad pipe_msg %d\n",
pipe_msg);
rc = -1;
done = True;
}
if (done)
{
char tmpDir[MAX_PATH];
DPRINTF(("FileOpPipeCB: done, rc %d\n", rc));
/* close the pipe and cancel the callback */
close(cb_data->pipe_m2s);
close(cb_data->pipe_s2m);
if (id != NULL)
XtRemoveInput(*id);
else
*fd = (rc == 0)? 0: -1;
/* arrange for modified directories to be updated */
DirectoryEndModify(cb_data->host, cb_data->directory);
/* Reposition the objects which have been modified */
if(!cb_data->finish_callback && cb_data->file_mgr_data)
{
char **file_set;
int actual_count=0;
/* Do this only if it is the current directory and Random placement
is ON */
if(cb_data->file_mgr_data->positionEnabled != RANDOM_OFF && strcmp(
cb_data->directory,cb_data->file_mgr_data->current_directory)==0)
{
file_set = (char **) XtCalloc(1,cb_data->file_count*sizeof(char *));
for(i=0;i<cb_data->file_count;i++)
{
if(cb_data->updates[i].operationStatus == True)
file_set[actual_count++] = cb_data->updates[i].file;
}
RepositionIcons(cb_data->file_mgr_data, file_set,actual_count,
G_dropx, G_dropy, True);
XtFree((char *)file_set);
file_set = NULL;
}
}
for(i = 0; i < desktop_data->numWorkspaces; i++)
DeselectAllDTFiles(desktop_data->workspaceData[i]);
for (i = 0; i < cb_data->file_count; i++)
{
char fileName[MAX_PATH];
/* Scroll the window to show the created object, since we
cannot keep scrolling for each object we just do it for
one object and we do it in case of Drag/Drop, but not
for Select.MoveTo/CopyTo ... */
if(!i && cb_data->callback_data == NULL)
{
FileMgrData *fmd;
if(cb_data && cb_data->file_mgr_data)
{
fmd = cb_data->file_mgr_data;
fmd->scrollToThisDirectory = XtNewString(cb_data->directory);
fmd->scrollToThisFile = XtNewString(cb_data->updates[i].file);
}
}
if (cb_data->updates[i].first_index == i)
{
if (cb_data->mode == MOVE_FILE)
{
DirectoryEndModify(cb_data->updates[i].host,
cb_data->updates[i].directory);
if( strcmp( cb_data->updates[i].directory, "/" ) == 0 )
tmpDir[0] = 0x0;
else
sprintf( tmpDir, "%s", cb_data->updates[i].directory );
}
if( cb_data->updates[i].host )
XtFree( cb_data->updates[i].host );
if( cb_data->updates[i].directory )
XtFree( cb_data->updates[i].directory );
if( cb_data->updates[i].app_man_dir )
XtFree( cb_data->updates[i].app_man_dir );
}
if( cb_data->mode == MOVE_FILE )
{
sprintf( fileName, "%s/%s", tmpDir, cb_data->updates[i].file );
if( cb_data->updates[i].operationStatus == True )
{
if( status == PIPEMSG_MOVE_TO_SAME_DIR )
{
RemoveIconFromWorkspace( fileName, cb_data->directory );
}
else if( status != PIPEMSG_FILEOP_ERROR )
{
ChangeWorkspaceIconLink(cb_data->file_mgr_data, fileName,
cb_data->directory,tmpDir );
/* If it is workspace drag and drop and the move operation
is not because of Select.MoveTo menu option */
if(initiating_view == NULL && cb_data->callback_data == NULL)
{
sprintf( fileName, "%s/%s", cb_data->directory,
cb_data->updates[i].file );
DtEliminateDots(fileName);
RemoveIconFromWorkspace( fileName, cb_data->directory );
}
}
}
}
XtFree(cb_data->updates[i].file);
}
status = 0;
/* call the callback routine */
if (cb_data->finish_callback)
(*cb_data->finish_callback)(cb_data->callback_data, rc);
/* free the callback data */
XtFree((char *)cb_data->updates);
XtFree((char *)cb_data->directory);
XtFree((char *)cb_data->host);
XtFree(client_data);
}
}
/*--------------------------------------------------------------------
* _FileMoveCopy
* Start the background process and set up callback for the pipe.
*------------------------------------------------------------------*/
static Boolean
_FileMoveCopy(
XtPointer data,
char *to_file,
char *directory,
char *host,
char **host_set,
char **file_set,
BufferInfo *buffer_set,
int file_count,
unsigned int modifiers,
DesktopRec *desktopWindow,
void (*finish_callback)(),
XtPointer callback_data)
{
static char *pname = "_FileMoveCopy";
int mode;
FileOpCBData *cb_data;
DirUpdate *updates;
int i, j;
char *ptr = NULL;
char *source_dir = NULL;
char *source_file = NULL;
int pipe_m2s[2];
int pipe_s2m[2];
int pid;
fd_set select_fds;
int fd;
struct timeval now, select_end, select_timeout;
Boolean operation_done;
int rc;
/* Determine the type of operation: move, copy, or link */
/* or creating buffers */
if (buffer_set != NULL)
{
mode = MAKE_BUFFER;
}
else
{
modifiers &= ~Button2Mask;
if (modifiers == ShiftMask)
mode = LINK_FILE;
else if (modifiers == ControlMask)
mode = COPY_FILE;
else
mode = MOVE_FILE;
}
/* set up the callback data structure */
cb_data = XtNew(FileOpCBData);
cb_data->desktop = (desktopWindow != NULL);
if (cb_data->desktop)
{
cb_data->file_mgr_data = NULL;
cb_data->file_mgr_rec = NULL;
cb_data->file_view_data = (FileViewData *)data;
cb_data->desktopWindow = desktopWindow;
}
else
{
if(data != NULL)
{
cb_data->file_mgr_data = (FileMgrData *)data;
cb_data->file_mgr_rec =
(FileMgrRec *) ((FileMgrData *)data)->file_mgr_rec;
}
else
{
cb_data->file_mgr_data = NULL;
cb_data->file_mgr_rec = NULL;
}
cb_data->file_view_data = NULL;
cb_data->desktopWindow = NULL;
}
cb_data->mode = mode;
cb_data->host = XtNewString(host);
cb_data->directory = XtNewString(directory);
cb_data->finish_callback = finish_callback;
cb_data->callback_data = callback_data;
/* mark the target directory as being modified in the directory cache */
DirectoryBeginModify(host, directory);
/* make a list of the operations to be done */
/* Allocate memory for the DirUpdateStructure */
cb_data->file_count = file_count;
cb_data->updates =
updates = (DirUpdate *)XtMalloc(file_count * sizeof(DirUpdate));
/* Determine whether we are dealing with files or buffers */
/* This affects how the updates structure is initialized */
if (mode == MAKE_BUFFER)
{
for (i=0; i< file_count; i++)
{
/* just simply set the the updates structure with */
/* the passed in file names */
updates[i].file = XtNewString(file_set[i]);
updates[i].bufferInfo.buf_ptr = buffer_set[i].buf_ptr;
updates[i].bufferInfo.size = buffer_set[i].size;
/* set unused updates fields to NOOP values */
updates[i].time_sent = FALSE;
updates[i].first_index = 0;
updates[i].host = NULL;
updates[i].directory = NULL;
updates[i].app_man_dir = NULL;
}
}
else
{
/* Seperate file names, directories, and hosts */
/* when dealing with real files */
for (i=0; i< file_count; i++)
{
/* get the name of the source directory */
ptr = strrchr(file_set[i], '/');
if (NULL != ptr)
{
if (ptr == file_set[i])
source_dir = "/";
else
{
*ptr = '\0';
source_dir = file_set[i];
}
source_file = ptr + 1;
}
else
{
source_dir = strdup(".");
source_file = file_set[i];
}
/* see if this directory is already in the list */
for (j = 0; j < i; j++)
if (strcmp(updates[j].host, host_set[i]) == 0 &&
strcmp(updates[j].directory, source_dir) == 0)
break;
if (j < i)
{ /* already in the list */
updates[i].host = updates[j].host;
updates[i].directory = updates[j].directory;
updates[i].app_man_dir = updates[j].app_man_dir;
}
else
{ /* not yet in the list */
updates[i].host = XtNewString(host_set[i]);
updates[i].directory = XtNewString(source_dir);
updates[i].app_man_dir = NULL;
if (!desktopWindow)
{
if(data != NULL)
{
if (((FileMgrData *)data)->toolbox)
updates[i].app_man_dir =
XtNewString(((FileMgrData *)data)->restricted_directory);
}
}
/* mark the directory as being modified in the directory cache */
if (mode == MOVE_FILE)
DirectoryBeginModify(updates[i].host, updates[i].directory);
}
updates[i].first_index = j;
updates[i].time_sent = False;
updates[i].operationStatus = False;
updates[i].file = XtNewString(source_file);
if (NULL != ptr) *ptr = '/';
}/* end for loop */
} /* endif */
/* create a pipe */
pipe(pipe_m2s);
pipe(pipe_s2m);
/* fork the process that does the actual work */
pid = fork();
if (pid == -1)
{
DirectoryAbortModify(host, directory);
for (i=0; i<file_count; i++)
if (mode == MOVE_FILE && updates[i].first_index == i)
DirectoryAbortModify(updates[i].host, updates[i].directory);
fprintf(stderr,
"%s: fork failed, ppid %d, pid %d: error %d=%s\n",
pname, getppid(), getpid(), errno, strerror(errno));
return False;
}
if (pid == 0)
{
DBGFORK(("%s: child forked, m2s %d s2m %d\n",
pname, pipe_m2s[0], pipe_s2m[1]));
close(pipe_m2s[1]); /* won't write to pipe_m2s */
close(pipe_s2m[0]); /* won't read from pipe_s2m */
if (desktopWindow != NULL)
rc = FileMoveCopyProcessDesktop(pipe_s2m[1], pipe_m2s[0],
directory, host, updates, file_count,
mode, desktopWindow);
else
rc = FileMoveCopyProcess(pipe_s2m[1], pipe_m2s[0], to_file, directory,
host, updates, file_count, mode, NULL);
DBGFORK(("%s: child exiting\n", pname));
exit(rc);
}
DBGFORK(("%s: forked child<%d>, m2s %d, s2m %d\n",
pname, pid, pipe_m2s[1], pipe_s2m[0]));
/* parent: set up callback to get the pipe data */
close(pipe_m2s[0]); /* won't read from pipe_m2s */
close(pipe_s2m[1]); /* won't write to pipe_s2m */
cb_data->pipe_m2s = pipe_m2s[1];
cb_data->pipe_s2m = pipe_s2m[0];
cb_data->mode = mode;
#ifdef __osf__
cb_data->child = pid;
#endif
/*
* We wait a certain amount of time for the background process to finish.
* If it doesn't finish within that time, we do the rest asynchronously.
*/
/* set up fd set for select */
FD_ZERO(&select_fds);
fd = pipe_s2m[0];
/* compute until what time we want to wait */
gettimeofday(&select_end, NULL);
select_end.tv_sec += FILE_MOVE_COPY_WAIT_TIME;
operation_done = False;
for (;;)
{
/* determine how much time is left */
gettimeofday(&now, NULL);
select_timeout.tv_sec = select_end.tv_sec - now.tv_sec;
select_timeout.tv_usec = select_end.tv_usec - now.tv_usec;
if (select_timeout.tv_usec < 0)
{
select_timeout.tv_sec--;
select_timeout.tv_usec += 1000000;
}
if ((int) select_timeout.tv_sec < 0)
{
/* check if our time is up */
DPRINTF(("FileMoveCopy: timed out; adding input callback\n"));
XtAppAddInput(XtWidgetToApplicationContext(toplevel),
pipe_s2m[0], (XtPointer)XtInputReadMask,
FileOpPipeCB, (XtPointer)cb_data);
break;
}
/* do the select */
FD_SET(fd, &select_fds);
#if defined(__hpux) && (OSMAJORVERSION <= 10) && (OSMINORVERSION < 2)
rc = select(fd + 1, (int *)&select_fds, NULL, NULL, &select_timeout);
#else
rc = select(fd + 1, &select_fds, NULL, NULL, &select_timeout);
#endif
if (rc < 0 && errno != EINTR)
{
perror("select failed in FileMoveCopy");
break;
}
else if (rc == 1)
{
/* call FileOpPipeCB to read & process the data from the pipe */
FileOpPipeCB((XtPointer)cb_data, &fd, NULL);
DPRINTF(("FileMoveCopy: FileOpPipeCB -> fd = %d\n", fd));
/*
* If the background process is done, FileOpPipeCB sets fd
* to zero (in case of success) or -1 (in case of failure).
*/
if (fd <= 0)
{
operation_done = (fd == 0);
break;
}
}
}
return operation_done;
}
/*--------------------------------------------------------------------
* FileMoveCopy, FileMoveCopyDesktop
* External entry points for invoking _FileMoveCopy
*------------------------------------------------------------------*/
Boolean
FileMoveCopy(
FileMgrData *file_mgr_data,
char *to_file,
char *directory,
char *host,
char **host_set,
char **file_set,
int file_count,
unsigned int modifiers,
void (*finish_callback)(),
XtPointer callback_data)
{
return _FileMoveCopy( (XtPointer)file_mgr_data, to_file, directory, host,
host_set, file_set, NULL, file_count, modifiers, NULL,
finish_callback, callback_data);
}
Boolean
FileMoveCopyDesktop(
FileViewData *file_view_data,
char * directory,
char ** host_set,
char ** file_set,
int file_count,
unsigned int modifiers,
DesktopRec *desktopWindow,
void (*finish_callback)(),
XtPointer callback_data)
{
return _FileMoveCopy ((XtPointer)file_view_data,
NULL,
directory,
home_host_name,
host_set,
file_set,
NULL,
file_count,
modifiers,
desktopWindow,
finish_callback,
callback_data);
}
/*====================================================================
*
* ChangeIconName
* Run a background process to rename an object.
*
*==================================================================*/
/*--------------------------------------------------------------------
* ChangeIconNameProcess:
* Main routine of the background process
*------------------------------------------------------------------*/
static int
ChangeIconNameProcess(
int pipe_fd,
char *host_name,
char *directory_name,
char *old_name,
char *new_name)
{
char * full_name, * old_full_name, *dir_path;
struct stat stat_buf;
long modify_time;
Boolean success;
short pipe_msg;
int rc;
Tt_status tt_status;
/* Check for uniqueness */
full_name = ResolveLocalPathName(host_name, directory_name, new_name, home_host_name, &tt_status);
if ( TT_OK != tt_status )
{
DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
pipe_msg = PIPEMSG_FILEOP_ERROR;
write(pipe_fd, &pipe_msg, sizeof(short));
XtFree(new_name);
return 1;
}
if (lstat(full_name, &stat_buf) == 0)
{
/* Name is not unique */
DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
pipe_msg = PIPEMSG_EXIST_ERROR;
write(pipe_fd, &pipe_msg, sizeof(short));
XtFree(full_name);
XtFree(new_name);
return 1;
}
/* send a modified message back through the pipe */
modify_time = 0;
dir_path = ResolveLocalPathName(host_name, directory_name, NULL, home_host_name, &tt_status);
if( TT_OK != tt_status )
{
DPRINTF(("ChadengeIconNameProcess: sending exist error\n"));
pipe_msg = PIPEMSG_FILEOP_ERROR;
write(pipe_fd, &pipe_msg, sizeof(short));
XtFree(full_name);
XtFree(new_name);
return 1;
}
if (stat(dir_path, &stat_buf) == 0)
modify_time = stat_buf.st_mtime;
XtFree(dir_path);
/* rename the file */
old_full_name = ResolveLocalPathName(host_name, directory_name, old_name, home_host_name, &tt_status);
if( TT_OK != tt_status )
{
DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
pipe_msg = PIPEMSG_FILEOP_ERROR;
write(pipe_fd, &pipe_msg, sizeof(short));
XtFree(full_name);
XtFree(new_name);
return 1;
}
success = FileManip((Widget)pipe_fd, MOVE_FILE, old_full_name, full_name, TRUE,
FileOpError, True, NOT_DESKTOP);
XtFree( old_full_name );
/* send a 'done' msg through the pipe */
rc = success? 0: -1;
if (rc == 0)
{
pipe_msg = PIPEMSG_FILE_MODIFIED;
write(pipe_fd, &pipe_msg, sizeof(short));
write(pipe_fd, &modify_time, sizeof(long));
}
DPRINTF(("ChangeIconNameProcess: sending DONE, rc %d\n", rc));
pipe_msg = PIPEMSG_DONE;
write(pipe_fd, &pipe_msg, sizeof(short));
write(pipe_fd, &rc, sizeof(int));
if (rc == 0)
PipeWriteString(pipe_fd, full_name);
XtFree( full_name );
return rc;
}
/*--------------------------------------------------------------------
* ChangeIconPipeCB:
* Read and process data sent through the pipe.
*------------------------------------------------------------------*/
static void
ChangeIconPipeCB(
XtPointer client_data,
int *fd,
XtInputId *id)
{
ChangeIconCBData *cb_data = (ChangeIconCBData *)client_data;
FileViewData *file_view_data = cb_data->file_view_data;
DesktopRec *desktopWindow = cb_data->desktopWindow;
Widget msg_widget;
DirectorySet *directory_set;
FileMgrData *file_mgr_data = NULL;
FileMgrRec *file_mgr_rec;
short pipe_msg;
int i, j, n;
int rc;
char *title, *err_msg, *err_arg;
long modify_time;
char *full_name;
char *tmpStr;
XmString label;
Arg args[3];
Boolean desktop_changed;
/* get widget for error messages */
if (cb_data->desktop)
{
msg_widget = XtParent(cb_data->w);
}
else
{
directory_set = (DirectorySet *)file_view_data->directory_set;
file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
msg_widget = file_mgr_rec->file_window;
}
/* read the msg from the pipe */
pipe_msg = -1;
n = PipeRead(*fd, &pipe_msg, sizeof(short));
DPRINTF(("ChangeIconPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
if (pipe_msg == PIPEMSG_FILE_MODIFIED)
{
/* get modify time */
PipeRead(*fd, &modify_time, sizeof(long));
/* mark the old & new files as modified in the directory cache */
if (modify_time != 0)
DirectoryModifyTime(cb_data->host_name, cb_data->directory_name,
modify_time);
DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
cb_data->old_name);
DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
cb_data->new_name);
return;
}
if (pipe_msg == PIPEMSG_EXIST_ERROR)
{
/* Name is not unique */
title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
if (cb_data->desktop)
{
tmpStr = GETMESSAGE(28,10, "An object with this name already exists in the original folder\n(The folder this object came from).\nPlease choose a different name.");
err_msg = XtNewString(tmpStr);
}
else
err_msg = XtNewString(GETMESSAGE(9,9, "A file with this name already exists.\nPlease choose a different name."));
_DtMessage (msg_widget, title, err_msg, NULL, HelpRequestCB);
XtFree(title);
XtFree(err_msg);
}
else if (pipe_msg == PIPEMSG_FILEOP_ERROR)
{
/* the rename failed */
PipeRead(*fd, &rc, sizeof(int));
err_msg = PipeReadString(*fd);
err_arg = PipeReadString(*fd);
FileOperationError(msg_widget, err_msg, err_arg);
XtFree(err_msg);
XtFree(err_arg);
}
else if (pipe_msg == PIPEMSG_DONE)
{
/* get the return code */
PipeRead(*fd, &rc, sizeof(int));
if (rc == 0)
{
/* the rename was successful */
full_name = PipeReadString(*fd);
/* All went well, destroy the text field */
XtUnmanageChild(cb_data->w);
XtDestroyWidget(cb_data->w);
/* Force the icon label to be updated immediately */
if (cb_data->desktop)
{
XmProcessTraversal(desktopWindow->iconGadget, XmTRAVERSE_CURRENT);
desktopWindow->text = NULL;
/* we'll catch this icon label in the loop after the else */
}
else
{
file_mgr_data->renaming = NULL;
label = XmStringCreateLocalized(cb_data->new_name);
XtSetArg(args[0], XmNstring, label);
XtSetValues(file_view_data->widget, args, 1);
XmStringFree(label);
XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
XmUpdateDisplay (file_mgr_rec->file_window);
/*
* To prevent the positional data from becoming disassociated with
* this file, we need to change the name in the positional data
* structure also.
*/
for (i = 0; i < file_mgr_data->num_objects; i++)
{
if (strcmp(cb_data->old_name,
file_mgr_data->object_positions[i]->name) == 0)
{
/* Found a match */
XtFree(file_mgr_data->object_positions[i]->name);
file_mgr_data->object_positions[i]->name =
XtNewString(cb_data->new_name);
break;
}
}
}
/*
* Check all desktop windows to see if they were linked to
* the file we just renamed. If so, we need to change the
* link in .dt/Desktop that points to it.
*
* Note: We could do this in a background process, but we assume
* that .dt/Desktop is local or, if it's remote and the remote server
* is down, the user is screwed anyway. So we assume it's ok to do
* blocking operations on .dt/Desktop in the main process.
* Hence we go for the simpler solution here.
*/
desktop_changed = False;
for (i = 0; i < desktop_data->numIconsUsed; i++)
{
desktopWindow = desktop_data->desktopWindows[i];
if (strcmp(cb_data->host_name, desktopWindow->host) == 0 &&
strcmp(cb_data->directory_name, desktopWindow->dir_linked_to) == 0
&& strcmp(cb_data->old_name, desktopWindow->file_name) == 0)
{
XmString label;
/* Force the icon label to be updated immediately */
label = XmStringCreateLocalized(cb_data->new_name);
XtSetArg(args[0], XmNstring, label);
XtSetValues(desktopWindow->iconGadget, args, 1);
XmStringFree(label);
XtFree(desktopWindow->file_name);
desktopWindow->file_name = XtNewString(cb_data->new_name);
XtFree(desktopWindow->file_view_data->file_data->file_name);
desktopWindow->file_view_data->file_data->file_name =
XtNewString(cb_data->new_name);
if( strcmp( desktopWindow->title, cb_data->old_name ) == 0 )
{
XtFree( desktopWindow->title );
desktopWindow->title = XtNewString( cb_data->new_name );
}
#ifdef SHAPE
GenerateShape(desktopWindow);
#endif
RegisterIconDropsDT(desktopWindow);
XmUpdateDisplay (desktopWindow->iconGadget);
desktop_changed = True;
}
}
if (desktop_changed)
{
SaveDesktopInfo(NORMAL_RESTORE);
CheckDesktop();
}
XtFree(full_name);
}
}
else
fprintf(stderr, "Internal error in ChangeIconPipeCB: bad pipe_msg %d\n",
pipe_msg);
/* arrange for the modified directory to be updated */
DirectoryEndModify(cb_data->host_name, cb_data->directory_name);
/* close the pipe and cancel the callback */
close(*fd);
XtRemoveInput(*id);
/* free callback data */
XtFree(cb_data->host_name);
XtFree(cb_data->directory_name);
XtFree(cb_data->old_name);
XtFree(cb_data->new_name);
XtFree((char *)cb_data);
}
/*--------------------------------------------------------------------
* _ChangeIconName:
* Start the background process and set up callback for the pipe.
*------------------------------------------------------------------*/
static void
_ChangeIconName (
Widget w,
Boolean desktop,
FileViewData *file_view_data,
DesktopRec *desktopWindow,
char *host_name,
char *directory_name)
{
static char *pname = "_ChangeIconName";
ChangeIconCBData *cb_data;
Arg args[3];
char *input_name;
char *new_name;
char *old_name;
char *title;
char *msg;
char *tmpStr;
int i, j;
int pipe_fd[2];
int pid;
int rc;
int dirNameLength = strlen (directory_name);
int maxFileNameLength = pathconf (directory_name, _PC_NAME_MAX);
int length;
/* get the new name */
XtSetArg(args[0], XmNvalue, &input_name);
XtSetArg(args[1], XmNuserData, &old_name);
XtGetValues(w, args, 2);
new_name = (char *)_DtStripSpaces(XtNewString(input_name));
length = strlen (new_name);
/* new name must be a simple name, no path */
msg = NULL;
if (DtStrchr (new_name, '/') != NULL)
msg = XtNewString(GetSharedMessage(LOCAL_RENAME_ONLY_ERROR));
#ifdef _CHECK_FOR_SPACES
else if (DtStrchr (new_name, ' ') != NULL ||
DtStrchr (new_name, '\t') != NULL)
{
msg = XtNewString(GetSharedMessage(NO_SPACES_ALLOWED_ERROR));
}
#endif
else if (length == 0 || strcmp(new_name, old_name) == 0)
{
/* Noop; simply remove the text field */
XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
XtFree(new_name);
if (desktop )
{
UnpostDTTextField();
}
else
{
DirectorySet *directory_set =
(DirectorySet *)file_view_data->directory_set;
FileMgrData *file_mgr_data =
(FileMgrData *)directory_set->file_mgr_data;
FileMgrRec *file_mgr_rec =
(FileMgrRec *)file_mgr_data->file_mgr_rec;
file_mgr_rec->menuStates |= RENAME;
UnpostTextField( file_mgr_data );
file_mgr_data->renaming = NULL;
}
return;
}
/* Ensure the new name has length less than or equal to the maximum
length that the system allows.
If maxFileNameLength == -1 the file system is not supporting POSIX, use MAXNAMLEN
*/
else if( maxFileNameLength < -1 || ( maxFileNameLength == -1 && ( length > MAXNAMLEN || length + dirNameLength > MAX_PATH ) ) || ( maxFileNameLength > 0 && length > maxFileNameLength ) )
{
msg = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
}
if (msg != NULL)
{
title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
_DtMessage (XtParent (w), title, msg, NULL, HelpRequestCB);
XtFree(title);
XtFree(msg);
XtFree (new_name);
return;
}
/* Check to see if the file has a representitive on the Desktop. */
if (desktopWindow == NULL)
{
for (i = 0; i < desktop_data->numIconsUsed; i++)
{
if (strcmp(host_name,
desktop_data->desktopWindows[i]->host) == 0 &&
strcmp(directory_name,
desktop_data->desktopWindows[i]->dir_linked_to) == 0 &&
strcmp(old_name, desktop_data->desktopWindows[i]->
file_view_data->file_data->file_name) == 0)
{
desktopWindow = desktop_data->desktopWindows[i];
break;
}
}
}
if (desktopWindow != NULL)
{
/*
* There is a representation of this file on the desktop:
* check if the there are any objects which match the new_name
*/
for (j = 0; j < desktop_data->numIconsUsed; j++)
{
if (strcmp(new_name, desktop_data->desktopWindows[j]->
file_view_data->file_data->file_name) == 0)
{
title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
if (desktop)
tmpStr = GETMESSAGE(28,9, "An object with this name already exists on the Workspace.\nPlease choose a different name.");
else
tmpStr = GETMESSAGE(9,90, "Name Conflict.\nThis object is out on the Workspace back drop.\nAnother object on the back drop already has the name you\nare trying to enter.\nPlease choose a different name.");
msg = XtNewString(tmpStr);
_DtMessage(XtParent (w), title, msg, NULL, HelpRequestCB);
XtFree(title);
XtFree(msg);
XtFree(new_name);
return;
}
}
}
/*
* Now we are ready to start the background process
* that does the actual rename.
*/
/* set up callback data */
cb_data = XtNew(ChangeIconCBData);
cb_data->w = w;
cb_data->desktop = desktop;
cb_data->file_view_data = file_view_data;
cb_data->desktopWindow = desktopWindow;
cb_data->host_name = XtNewString(host_name);
cb_data->directory_name = XtNewString(directory_name);
cb_data->old_name = XtNewString(old_name);
cb_data->new_name = new_name;
/* mark the directory as being modified in the directory cache */
DirectoryBeginModify(host_name, directory_name);
/* create a pipe */
pipe(pipe_fd);
/* fork the process that does the actual work */
pid = fork();
if (pid == -1)
{
DirectoryAbortModify(host_name, directory_name);
fprintf(stderr,
"%s: fork failed, ppid %d, pid %d: error %d=%s\n",
pname, getppid(), getpid(), errno, strerror(errno));
return;
}
if (pid == 0)
{
DBGFORK(("%s: child forked, pipe %d\n", pname, pipe_fd[1]));
close(pipe_fd[0]); /* child won't read from the pipe */
rc = ChangeIconNameProcess(pipe_fd[1], host_name, directory_name,
old_name, new_name);
close(pipe_fd[1]);
DBGFORK(("%s: child exiting\n", pname));
exit(rc);
}
DBGFORK(("%s: forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
/* parent: set up callback to get the pipe data */
close(pipe_fd[1]); /* parent won't write the pipe */
cb_data->child = pid;
XtAppAddInput(XtWidgetToApplicationContext(toplevel),
pipe_fd[0], (XtPointer)XtInputReadMask,
ChangeIconPipeCB, (XtPointer)cb_data);
}
void
ChangeIconName (
Widget w,
XtPointer client_data,
XmTextVerifyCallbackStruct * call_data)
{
int value, size, increment, page;
Arg args[3];
FileMgrData *file_mgr_data = (FileMgrData *)client_data;
FileMgrRec *file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
DirectorySet *directory_set = (DirectorySet *)(file_mgr_data->renaming->directory_set);
if (call_data->reason == XmCR_MODIFYING_TEXT_VALUE ||
call_data->reason == XmCR_MOVING_INSERT_CURSOR )
{
int SWwidth;
/* x1 - x value of the text widget with respect to scroll window
x2,y2 - x,y values of the cursor position (new) w.r.t text widget
x3,y3 - x,y values of the cursor position (previous) w.r.t textW
*/
Position x1,x2,y2,x3,y3;
/* width of the text widget */
Dimension stringWidth;
XtSetArg(args[0],XmNx,&x1);
XtGetValues(w,args,1);
if(XtIsManaged(file_mgr_rec->vertical_scroll_bar))
SWwidth=(file_mgr_rec->scroll_window->core.width -
file_mgr_rec->vertical_scroll_bar->core.width);
else
SWwidth=file_mgr_rec->scroll_window->core.width;
XmTextFieldPosToXY(w,call_data->newInsert,&x2,&y2);
XmTextFieldPosToXY(w,call_data->currInsert,&x3,&y3);
XtSetArg(args[0],XmNwidth,&stringWidth);
XtGetValues(w,args,1);
/*
printf("\n x2=%d x1=%d x3=%d\n",x2,x1,x3);
*/
if ( (Dimension)(call_data->newInsert) < stringWidth )
{
if( XtIsManaged(file_mgr_rec->horizontal_scroll_bar) )
{
XmScrollBarGetValues( file_mgr_rec->horizontal_scroll_bar,
&value, &size, &increment, &page);
/*
printf("\n value = %d",value);
*/
/* case where cursor is moved forward */
if( (x2-x3) > 0)
{
int max=0;
XtSetArg (args[0], XmNmaximum, &max);
XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
if( (value < (max-size)) &&
((x1+x2) - value > 0 ) &&
( (Position)(((x1+x2) - value) +
file_mgr_rec->vertical_scroll_bar->core.width) > (Position) SWwidth ) )
{
if( (value+(x2-x3)) > (max-size) )
value = (max-size);
else
value += (x2-x3);
XmScrollBarSetValues(
file_mgr_rec->horizontal_scroll_bar,
value, size, increment, page,True
);
}
}
/* case where cursor is moved in reverse direction */
else if( (x2-x3) < 0 )
{
int min=0;
XtSetArg (args[0], XmNminimum, &min);
XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
if( (value > min) && ((Position)(x1+x3) < (Position)(value+
file_mgr_rec->vertical_scroll_bar->core.width)) )
{
if( (x2 <= 0) || ((value - (x3-x2)) < min) )
value = min;
else
value -= (x3-x2);
XmScrollBarSetValues(file_mgr_rec->horizontal_scroll_bar,
value, size, increment, page,True
);
}
}
}
}
return;
}
_ChangeIconName (w, False, file_mgr_data->renaming, NULL,
file_mgr_data->host, directory_set->name);
}
void
ChangeIconNameDT (
Widget w,
XtPointer client_data,
XtPointer call_data)
{
DesktopRec * desktopWindow = (DesktopRec *)client_data;
_ChangeIconName (w, True, desktopWindow->file_view_data, desktopWindow,
desktopWindow->host, desktopWindow->dir_linked_to);
}
/*====================================================================
*
* MakeFile
* Run a background process to create a file or directory.
*
*==================================================================*/
/*--------------------------------------------------------------------
* GetTarget
* Build a host, directory, and file name path to be used as the
* destination of a create, copy or move operation.
*------------------------------------------------------------------*/
void
GetTarget(
char *from_host,
char *from_dir,
char *new_name,
char *to_host,
char *to_dir,
char *to_file)
{
char *ptr;
strcpy(to_host, from_host);
if (strncmp (new_name, "/", 1) == 0)
{
strcpy(to_dir, new_name);
}
else
{
if (strcmp(to_dir, "/") == 0)
sprintf(to_dir, "%s%s", from_dir, new_name);
else
sprintf(to_dir, "%s/%s", from_dir, new_name);
}
ptr = strrchr(to_dir, '/');
*ptr = '\0';
strcpy(to_file, ptr + 1);
}
/*--------------------------------------------------------------------
* MakeFileProcess
* Main routine of background process for MakeFile
*------------------------------------------------------------------*/
static int
MakeFileProcess(
int pipe_fd,
char *to_host,
char *to_dir,
char *to_file,
unsigned char type)
{
char *to;
struct stat stat_buf;
char *dir_path;
long modify_time;
short pipe_msg;
int fnew;
int rc;
Tt_status tt_status;
/* assume success */
rc = 0;
/* get the full name of the file/dir to be created */
to = ResolveLocalPathName(to_host, to_dir, to_file, home_host_name, &tt_status);
if (to == NULL)
rc = EINVAL;
/* check if a file/dir with the same name already exists */
else if (lstat (to, &stat_buf) == 0)
rc = EEXIST;
/* now create the file/dir */
else
{
/* send a modified message back through the pipe */
modify_time = 0;
dir_path = ResolveLocalPathName(to_host, to_dir, NULL, home_host_name, &tt_status);
if (stat(dir_path, &stat_buf) == 0)
modify_time = stat_buf.st_mtime;
XtFree(dir_path);
pipe_msg = PIPEMSG_FILE_MODIFIED;
write(pipe_fd, &pipe_msg, sizeof(short));
write(pipe_fd, &modify_time, sizeof(long));
/* do the work */
if (type == DtDIRECTORY)
{
if (mkdir (to, (int) DtFILE_DIR_CREATION_MASK) != 0)
rc = errno;
}
else
{
unsigned int mode;
if (type == DtDATA)
mode = DtFILE_DATA_CREATION_MASK;
else
mode = DtFILE_OTHER_CREATION_MASK;
if ((fnew = creat(to, (int) mode)) < 0)
rc = errno;
else
close(fnew);
}
}
/* send a 'done' msg through the pipe */
pipe_msg = PIPEMSG_DONE;
DPRINTF(("MakeFileProcess: sending DONE, rc %d\n", rc));
write(pipe_fd, &pipe_msg, sizeof(short));
write(pipe_fd, &rc, sizeof(int));
PipeWriteString(pipe_fd, to);
XtFree(to);
return rc;
}
/*--------------------------------------------------------------------
* MakeFilePipeCB:
* Read and process data sent through the pipe.
*------------------------------------------------------------------*/
static void
MakeFilePipeCB(
XtPointer client_data,
int *fd,
XtInputId *id)
{
MakeFileCBData *cb_data = (MakeFileCBData *)client_data;
short pipe_msg;
int n;
long modify_time;
char *full_name;
int rc;
/* read the msg from the pipe */
pipe_msg = -1;
n = PipeRead(*fd, &pipe_msg, sizeof(short));
if (pipe_msg == PIPEMSG_FILE_MODIFIED)
{
/* get modify time */
PipeRead(*fd, &modify_time, sizeof(long));
/* mark the file updated in the directory cache */
if (modify_time != 0)
DirectoryModifyTime(cb_data->to_host, cb_data->to_dir, modify_time);
DirectoryFileModified(cb_data->to_host, cb_data->to_dir,
cb_data->to_file);
return;
}
if (pipe_msg == PIPEMSG_DONE)
{
PipeRead(*fd, &rc, sizeof(int));
full_name = PipeReadString(*fd);
}
else
{
fprintf(stderr, "Internal error in MakeFilePipeCB: bad pipe_msg %d\n",
pipe_msg);
rc = -1;
full_name = NULL;
}
DPRINTF(("MakeFilePipeCB: n %d, pipe_msg %d, rc %d\n", n, pipe_msg, rc));
/* arrange for the modified directory to be updated */
DirectoryEndModify(cb_data->to_host, cb_data->to_dir);
/* close the pipe and cancel the callback */
close(*fd);
XtRemoveInput(*id);
/* Store away the newly created file so we later on we can
scroll to it.
*/
{
MakeFileDoneData * data = (MakeFileDoneData *)cb_data->callback_data;
DialogCallbackStruct * call_struct = data->call_struct;
FileMgrData * file_mgr_data = call_struct->file_mgr_data;
file_mgr_data->scrollToThisDirectory = cb_data->to_dir;
file_mgr_data->scrollToThisFile = cb_data->to_file;
}
/* call the callback routine */
if (cb_data->finish_callback)
(*cb_data->finish_callback)(cb_data->callback_data, full_name, rc);
/* free callback data */
XtFree(full_name);
XtFree(cb_data->to_host);
/* Don't free to_dir and to_file. We used this to remember
which file so later on we can scroll to it.
XtFree(cb_data->to_dir);
XtFree(cb_data->to_file);
*/
XtFree((char *)cb_data);
}
/*--------------------------------------------------------------------
* MakeFile:
* Start the background process and set up callback for the pipe.
*------------------------------------------------------------------*/
void
MakeFile(
Widget w,
char *host_name,
char *directory_name,
char *new_name,
unsigned char type,
void (*finish_callback)(),
XtPointer callback_data)
{
static char *pname = "MakeFile";
MakeFileCBData *cb_data;
char to_host[MAX_PATH];
char to_dir[MAX_PATH];
char to_file[MAX_PATH];
int pipe_fd[2];
int pid;
int rc;
/* get host & path of the target file */
GetTarget(host_name, directory_name, new_name, to_host, to_dir, to_file);
/* mark the target directory as being modified in the directory cache */
DirectoryBeginModify(to_host, to_dir);
/* parent: set up callback to get the pipe data */
cb_data = XtNew(MakeFileCBData);
cb_data->to_host = XtNewString(to_host);
cb_data->to_dir = XtNewString(to_dir);
cb_data->to_file = XtNewString(to_file);
cb_data->finish_callback = finish_callback;
cb_data->callback_data = callback_data;
/* create a pipe */
pipe(pipe_fd);
/* fork the process that does the actual work */
pid = fork();
if (pid == -1)
{
DirectoryAbortModify(to_host, to_dir);
fprintf(stderr,
"%s: fork failed, ppid %d, pid %d: error %d=%s\n",
pname, getppid(), getpid(), errno, strerror(errno));
return;
}
if (pid == 0)
{
/* child process */
DBGFORK(("%s: child forked, pipe %d\n", pname, pipe_fd[1]));
close(pipe_fd[0]); /* child won't read from the pipe */
rc = MakeFileProcess(pipe_fd[1], to_host, to_dir, to_file, type);
close(pipe_fd[1]);
DBGFORK(("%s: child exiting\n", pname));
exit(rc);
}
DBGFORK(("%s: forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
/* parent: set up callback to get the pipe data */
close(pipe_fd[1]); /* parent won't write the pipe */
cb_data->child = pid;
XtAppAddInput(XtWidgetToApplicationContext(toplevel),
pipe_fd[0], (XtPointer)XtInputReadMask,
MakeFilePipeCB, (XtPointer)cb_data);
}
/*=============================================================
*
* The following routines handle the creation of files from
* buffers: MakeFilesFromBuffers and MakeFilesFromBuffersDT
* follow
*
*=============================================================*/
Boolean
MakeFilesFromBuffers(
FileMgrData *file_mgr_data,
char * directory,
char *host,
char **file_set,
char **host_set,
BufferInfo *buffer_set,
int num_of_buffers,
void (*finish_callback)(),
XtPointer callback_data)
{
return _FileMoveCopy ((XtPointer)file_mgr_data, NULL, directory, host,
host_set, file_set, buffer_set, num_of_buffers,
0, NULL, finish_callback, callback_data);
}
Boolean
MakeFilesFromBuffersDT(
FileViewData *file_view_data,
char * directory,
char **file_set,
char **host_set,
BufferInfo *buffer_set,
int num_of_buffers,
DesktopRec *desktopWindow,
void (*finish_callback)(),
XtPointer callback_data)
{
return _FileMoveCopy ((XtPointer)file_view_data, NULL, directory,
home_host_name,
host_set, file_set, buffer_set, num_of_buffers,
0, desktopWindow, finish_callback, callback_data);
}
/*====================================================================
*
* CreateFileFromBuffer
* Routine to create a file from a buffer
*
*==================================================================*/
static Boolean
CreateFileFromBuffer(int pipe_s2m,
char *directory,
char *fully_qualified_name,
void *buffer,
int size)
{
int fnew;
int rc=0;
unsigned int mode;
Boolean BufferIsExecutable=FALSE;
char *err_msg, *err_arg, *tmpStr;
char *format_str, *strerror_str;
int format_param_len=20;
int savedError = 0;
/* Set the permissions depending if buffer is a */
/* file or an execuatable */
if (_DtIsBufferExecutable(buffer,size))
{
mode = S_IRUSR | S_IWUSR | S_IXUSR |
S_IRGRP | S_IWGRP | S_IXGRP |
S_IROTH | S_IWOTH | S_IXOTH;
}
else
{
mode = S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH;
}
/* Create the target file */
if ((fnew = open(fully_qualified_name, O_CREAT| O_WRONLY, mode)) < 0)
{
DPRINTF(("CreateBufferFromFile: Could not create %s\n",
fully_qualified_name));
savedError = errno;
rc = -1;
}
else
{
/* Write the buffer to the target file */
if ((rc = write(fnew, buffer, size)) < 0 )
{
DPRINTF (("CreateBufferFromFile: Could not write buffer to %s\n",
fully_qualified_name));
savedError=errno;
}
else
{
close(fnew);
DPRINTF (("CreateBuffeFromFile: Target file %s created\n",
fully_qualified_name));
}
}
/* Handle errors */
if (rc < 0)
{
switch (savedError)
{
case EACCES:
tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
err_msg = XtNewString(tmpStr);
err_arg = XtNewString(fully_qualified_name);
DPRINTF (("CreateBufferFromFile: EACCESS errno is %d\n",errno));
break;
default :
err_msg = strerror(savedError);
err_arg = NULL;
DPRINTF (("CreateBufferFromFile: %s\n", err_msg));
} /* endswitch */
/* Write error message on pipe so */
/* that the parent process will */
/* display a dialog */
PipeWriteErrmsg(pipe_s2m, rc, err_msg, err_arg);
if (err_msg) XtFree(err_msg);
if (err_arg) XtFree(err_arg);
return FALSE;
}
else
{
return TRUE;
}
}
/*
* DisplayDuplicateOpError - Used in FileOpPipeCallback when a duplicate
* operation like move/copy/link a file onto the same file is performed,
* this routine gets called and displays an error message.
*/
static void
DisplayDuplicateOpError(
FileOpCBData *cb_data,
int index)
{
char *msgptr,*err_msg,*title,*tchar;
Widget dialogwidget;
if (cb_data->mode == MOVE_FILE)
{
if(cb_data->callback_data == NULL)
if(initiating_view == NULL)
return;
else
{
title = XtCalloc(1,strlen(GETMESSAGE(9,73,"Move"))+
strlen(GETMESSAGE(9,94,"Error"))+5);
tchar = XtNewString(GETMESSAGE(9,73,"Move"));
sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
XtFree(tchar);
err_msg = GETMESSAGE(11,135,"Cannot move object %s onto itself");
}
}
else if (cb_data->mode == COPY_FILE)
{
title = XtCalloc(1,strlen(GETMESSAGE(9,72,"Copy"))+
strlen(GETMESSAGE(9,94,"Error"))+5);
tchar = XtNewString(GETMESSAGE(9,72,"Copy"));
sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
XtFree(tchar);
if(cb_data->callback_data == NULL)
{
if(cb_data->file_mgr_data && cb_data->file_mgr_data->toolbox)
{
XtFree(title);
return;
}
else
err_msg = GETMESSAGE(11,136,"Cannot copy object %s onto itself");
}
else
{
err_msg = GETMESSAGE(11,45,"No Copy Operation performed on object %s.\nYou must change either the Destination Folder\nor the Name for Copy before a copy can be created");
}
}
else
{
title = XtCalloc(1,strlen(GETMESSAGE(9,74,"Link"))+
strlen(GETMESSAGE(9,94,"Error"))+5);
tchar = XtNewString(GETMESSAGE(9,74,"Link"));
sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
XtFree(tchar);
if(cb_data->callback_data == NULL)
{
err_msg = GETMESSAGE(11,137,"Cannot link object %s onto itself");
}
else
{
err_msg = GETMESSAGE(11,46,"No Link Operation performed on object %s.\nYou must change either the Destination Folder\nor the Name for Copy before a link can be created");
}
}
msgptr = XtCalloc(1,strlen(err_msg)+strlen(cb_data->updates[index].file)+10);
sprintf(msgptr,err_msg,cb_data->updates[index].file);
if(cb_data->callback_data)
dialogwidget = ((RenameDoneData *)(cb_data->callback_data))->w;
else
dialogwidget = toplevel;
_DtMessage (dialogwidget,title, msgptr, NULL, HelpRequestCB);
XtFree(msgptr);
XtFree(title);
}
/*==============================================================
*
* appendErrorMessage
*
* if "arg" is not null, "new" is assumed to include %s
* "message" is re-allocated and so will have a different
* address than when the function was called
*
* usage: errorMsg = appendErrorMessage(errorMsg,errStr,file);
*
*==============================================================
*/
static String
appendErrorMessage(String message, String new, String arg)
{
String newMessage;
if (arg == NULL)
newMessage = XtNewString(new);
else
{
newMessage = XtMalloc(strlen(new) + strlen(arg) + 1);
sprintf(newMessage,new,arg);
}
if (message == NULL)
{
message = XtRealloc(message, (strlen(newMessage) + 2));
*message = '\0';
}
else
message = XtRealloc(message, (strlen(message) + strlen(newMessage) + 2));
strcat(message,newMessage);
strcat(message,"\n");
XtFree(newMessage);
return message;
} /* end appendErrorMessage */
static void
DisplayErrorMessage(
int pipe_s2m,
char *errMsg,
char *from,
char *tdir)
{
char *localstr;
localstr = (char *) XtMalloc(strlen(errMsg)+strlen(from)+strlen(tdir) + 10 );
sprintf(localstr,errMsg,tdir,from);
PipeWriteErrmsg(pipe_s2m, -1, localstr, NULL);
XtFree(localstr);
}
static Boolean
IsInParentDir(
char *source_path ,
char *dest_path )
{
char filename [MAX_PATH];
char *cptr;
int slen = strlen(source_path);
if(slen > strlen(dest_path))
return False;
strcpy (filename, dest_path);
cptr = strchr(&filename[slen-1],'/');
if(cptr)
*cptr = '\0';
return ((strcmp(source_path,filename) == 0)?True:False);
}