2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: FileOp.c /main/14 1999/12/09 13:06:21 mgreess $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 * COMPONENT_NAME: Desktop
31 * DESCRIPTION: File processing functions.
33 * FUNCTIONS: ChangeIconName
35 * ChangeIconNameProcess
37 * CreateFileFromBuffer
38 * DisplayDuplicateOpError
43 * FileMoveCopyProcessDesktop
50 * MakeFilesFromBuffers
51 * MakeFilesFromBuffersDT
56 * RemoveIconFromWorkspace
57 * ChangeWorkspaceIconLink
65 * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
66 * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
67 * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
68 * (c) Copyright 1993, 1994, 1995 Novell, Inc.
70 ****************************************************************************
71 ************************************<+>*************************************/
76 #include <sys/types.h>
78 #include <sys/signal.h>
87 #include <sys/select.h>
90 #if defined(_AIX)|| defined(hpux)
100 #include <Xm/MwmUtil.h>
101 #include <Xm/TextF.h>
102 #include <Xm/ScrollBar.h>
103 #include <X11/ShellP.h>
104 #include <X11/Shell.h>
105 #include <X11/Xutil.h>
106 #include <X11/Xatom.h>
109 #include <X11/extensions/shape.h>
113 #include <Dt/IconP.h>
114 #include <Dt/IconFile.h>
115 #include <Dt/Action.h>
116 #include <Dt/Connect.h>
118 #include <Dt/DtNlUtils.h>
119 #include <Dt/HourGlass.h>
120 #include <Dt/SharedProcs.h>
125 #include "SharedProcs.h"
133 #include "SharedMsgs.h"
134 #include "sharedFuncs.h"
137 /* Static Function declarations */
139 static Boolean CreateFileFromBuffer(
142 char *fully_qualified_name,
145 static String appendErrorMessage(
149 static void DisplayErrorMessage(
154 static Boolean IsInParentDir(char *from,char *to);
156 /* the amount of time we wait for a file move/copy to complete */
157 /* @@@ should make this a resource */
158 #define FILE_MOVE_COPY_WAIT_TIME 2
161 /* types of messages sent through the pipe */
162 #define PIPEMSG_FILEOP_ERROR 1
163 #define PIPEMSG_EXIST_ERROR 2
164 #define PIPEMSG_OTHER_ERROR 3
165 #define PIPEMSG_CONFIRM 4
166 #define PIPEMSG_TARGET_TIME 5
167 #define PIPEMSG_FILE_MODIFIED 6
168 #define PIPEMSG_DONE 7
169 #define PIPEMSG_REPLACE_RENAME 8
170 #define PIPEMSG_REPLACE_RENAME_SAME 9
171 #define PIPEMSG_REPLACE_MERGE 10
172 #define PIPEMSG_MULTICOLLIDE 11
173 #define PIPEMSG_MULTICOLLIDE_SAME 12
174 #define PIPEMSG_MOVE_TO_SAME_DIR 13
176 /* the following messages are also defined & used in OverWrite.c */
177 #define PIPEMSG_CANCEL 101
178 #define PIPEMSG_PROCEED 102
179 #define PIPEMSG_MERGE 103
180 #define PIPEMSG_REPLACE_BUFFER 104
181 #define PIPEMSG_RENAME_BUFFER 105
182 #define PIPEMSG_MULTI_PROCEED 106
184 extern int G_dropx,G_dropy;
186 /* callback data for file move/copy/link */
191 BufferInfo bufferInfo;
194 Boolean operationStatus;
201 FileMgrData *file_mgr_data;
202 FileMgrRec *file_mgr_rec;
203 FileViewData *file_view_data;
204 DesktopRec *desktopWindow;
205 int pipe_m2s; /* pipe main to slave */
206 int pipe_s2m; /* pipe slave to main */
212 void (*finish_callback)();
213 XtPointer callback_data;
218 /* callback data for file rename */
223 FileViewData *file_view_data;
224 DesktopRec *desktopWindow;
226 char *directory_name;
233 /* callback data for create file/directory */
239 void (*finish_callback)();
240 XtPointer callback_data;
246 DisplayDuplicateOpError(FileOpCBData *cb_data,int index);
250 /*====================================================================
252 * Routine for sending data through a pipe
254 *==================================================================*/
256 /*--------------------------------------------------------------------
258 * Read data from the pipe
259 *------------------------------------------------------------------*/
267 static int whined_fd = -1;
273 rc = read(fd, (char *)buf + n, len - n);
276 else if (rc < 0 && errno == EINTR)
286 "PipeRead: broken pipe, ppid=%d pid=%d fd=%d\n",
287 getppid(), getpid(), fd);
292 perror("dtfile: read failed in PipeRead");
303 /*--------------------------------------------------------------------
305 * write a string to the pipe
306 *------------------------------------------------------------------*/
316 oldPipe = (void (*)())signal(SIGPIPE, SIG_IGN);
323 if (write(fd, &len, sizeof(short)) < 0) {
328 sent = write(fd, s, len);
330 signal(SIGPIPE, oldPipe);
336 /*--------------------------------------------------------------------
338 * read a string from the pipe
339 *------------------------------------------------------------------*/
350 if (PipeRead(fd, &len, sizeof(short)) != sizeof(short))
357 s = (char *)XtMalloc(len + 1);
358 if (PipeRead(fd, s, len) != len)
369 /*--------------------------------------------------------------------
371 * write an error message to the pipe
372 *------------------------------------------------------------------*/
381 short pipe_msg = PIPEMSG_FILEOP_ERROR;
383 DPRINTF(("PipeWriteErrmsg: sending error %d \"%s\"\n", rc, msg));
385 write(fd, &pipe_msg, sizeof(short));
386 write(fd, &rc, sizeof(int));
387 PipeWriteString(fd, msg);
388 PipeWriteString(fd, arg);
394 /*====================================================================
397 * Run a background process to move/copy/link files dropped
398 * on a dtfile window or icon.
400 *==================================================================*/
402 /*--------------------------------------------------------------------
403 * moveCopyLinkCancel:
404 * Cancel-button callback for overwrite confirmation dialog
405 *------------------------------------------------------------------*/
407 int filop_confirm_fd = -1; /* @@@ can't we pass this in client_data? */
412 XtPointer client_data,
413 XtPointer call_data )
415 const int rc = PIPEMSG_CANCEL;
417 /* close the dialog */
418 XtUnmanageChild((Widget)client_data);
419 XmUpdateDisplay((Widget)client_data);
420 XtDestroyWidget((Widget)client_data);
422 /* send return code through the pipe to the background proc */
423 write(filop_confirm_fd, &rc, sizeof(int));
424 filop_confirm_fd = -1;
428 /*--------------------------------------------------------------------
430 * Ok-button callback for overwrite confirmation dialog
431 *------------------------------------------------------------------*/
436 XtPointer client_data,
437 XtPointer call_data )
439 const int rc = PIPEMSG_PROCEED;
441 /* close the dialog */
442 XtUnmanageChild((Widget)client_data);
443 XmUpdateDisplay((Widget)client_data);
444 XtDestroyWidget((Widget)client_data);
446 /* send affirmative return code through the pipe to the background proc */
447 write(filop_confirm_fd, &rc, sizeof(int));
448 filop_confirm_fd = -1;
452 /*--------------------------------------------------------------------
454 * Error handler for FileManip when called in the background process
455 *------------------------------------------------------------------*/
463 int pipe_fd = (int) (intptr_t) w; /* @@@ Hack! @@@
464 In the background process we call FileManip with
465 the file descriptor for the pipe instead of a
466 widget id. We rely on the fact that FileManip
467 never uses the widget as a widget, but only
468 passes it to the error handler. */
470 /* write the error message to the pipe */
471 PipeWriteErrmsg(pipe_fd, -1, message1, message2);
475 /*--------------------------------------------------------------------
477 * Send a message through the pipe that informs the main process
478 * that we are about to modify a directory or that a file has been
480 *------------------------------------------------------------------*/
495 struct stat stat_buf;
498 /* if first operation on target dir, send timestamp */
501 if (stat(to, &stat_buf) == 0)
503 modify_time = stat_buf.st_mtime;
504 pipe_msg = PIPEMSG_TARGET_TIME;
505 write(pipe_fd, &pipe_msg, sizeof(short));
506 write(pipe_fd, &modify_time, sizeof(long));
510 /* if first operation on source dir, get timestamp of source dir */
512 j = updates[i].first_index;
513 if (mode == MOVE_FILE && !updates[j].time_sent)
517 dir_path = ResolveLocalPathName(updates[i].host,
518 updates[i].directory,
523 if (stat(dir_path, &stat_buf) == 0)
524 modify_time = stat_buf.st_mtime;
526 updates[j].time_sent = True;
529 /* send the modify message */
530 pipe_msg = PIPEMSG_FILE_MODIFIED;
531 write(pipe_fd, &pipe_msg, sizeof(short));
532 write(pipe_fd, &i, sizeof(int));
533 write(pipe_fd, &modify_time, sizeof(long));
534 PipeWriteString(pipe_fd, target_file);
537 /*--------------------------------------------------------------------
538 * FileMoveCopyProcess:
539 * Main routine of the background process
541 * This routine has two basic modes of operation:
542 * It is given a list of source files and a target directory,
543 * and performs an operation on the source files. This mode
544 * is used for drag & drop operations where a user can
545 * select multiple source files and then drop them on a
546 * target directory to either move, copy, or copy-as-link
547 * the source files to the target directory. The source
548 * and target directories must be different.
549 * It is given a single source file and a target file. The
550 * target can be either a directory or a file. This mode
551 * is used for menu-intiated move, copy, or copy-as-link
552 * operations. The source and target directories can be
554 * The source file(s) are given in updates; the destination is
555 * in host, dirctory, to_file. If to_file is NULL, the
556 * first mode (drag & drop) is assumed, otherwise assume
557 * menu-initiated mode.
559 *------------------------------------------------------------------*/
571 DesktopRec *desktopWindow)
573 char * target_dir, * from, * to;
574 int i, j, rc, result;
575 Boolean return_val = False;
578 char *tmpStr, *target_file;
579 struct stat stat_buf, from_stat_buf;
583 int *sameIndex = NULL, *sameConfirmType = NULL;
584 Boolean first_op = True;
588 String permissionErrors = NULL;
589 Boolean targetChecked = FALSE;
590 Boolean targetError = FALSE;
591 Boolean CopyError=FALSE,MoveError1=FALSE,MoveError2=FALSE;
592 char *CopyString=NULL,*MoveString1=NULL,*MoveString2=NULL;
595 /* Get the fully qualified destination path. */
596 target_dir = (char *)ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
597 if( TT_OK != tt_status )
599 char msg1[2*MAX_PATH];
601 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
602 directory, host, host);
604 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
605 directory, host, host);
607 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
608 pipe_msg = PIPEMSG_FILEOP_ERROR;
610 write(pipe_s2m, &pipe_msg, sizeof(short));
611 write(pipe_s2m, &rc, sizeof(int));
615 DtEliminateDots(target_dir);
617 for (i = 0; i < file_count; i++)
621 /* get full name of the source file, if just */
622 /* dealing with regular files */
623 if (mode != MAKE_BUFFER)
625 from = ResolveLocalPathName(updates[i].host,
626 updates[i].directory,
632 char msg1[2*MAX_PATH];
635 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
636 updates[i].directory, updates[i].host, updates[i].host);
638 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
639 updates[i].directory, updates[i].host, updates[i].host);
641 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
645 /* do some extra error checking if a target filename is specified */
646 /* this is meant for the case of a menu-initiated operation */
649 /* Verify that the target directory already exists */
650 if ( (stat(target_dir, &stat_buf) != 0) ||
651 (! S_ISDIR(stat_buf.st_mode) ) )
656 GETMESSAGE(11,41,"The folder\n%s\ndoes not exist."));
657 PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
665 /* check for a drop of a directory onto itself */
666 if (updates[i].app_man_dir)
668 char *temp_dir = XtNewString(target_dir);
670 temp_dir = _DtResolveAppManPath(temp_dir, updates[i].app_man_dir);
671 if (mode == MOVE_FILE && strcmp(temp_dir, from) == 0)
676 GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
677 PipeWriteErrmsg( pipe_s2m, -1, msg, temp_dir );
686 else if (mode == MOVE_FILE && strcmp(target_dir, from) == 0)
691 GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
692 PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
698 else if (mode == MOVE_FILE && stat(from, &stat_buf) == 0 &&
699 S_ISDIR(stat_buf.st_mode) && DirectoryBusy(from))
703 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."));
705 PipeWriteErrmsg( pipe_s2m, -1, msg, from );
713 /* for copy operations, check for read permission on the source file */
714 /* the error message is appended to a list and dealt with later */
715 /* the current file is not processed */
716 if (mode == COPY_FILE)
717 if (CheckAccess(from,R_OK) == -1)
722 /* 'errno' is not giving correct results like 'ENOENT' in order to
723 use it here, may be because of the other system calls in
726 if (stat(from, &sbuf) < 0)
727 tmpStr = (GETMESSAGE(28,13,"Object:\n\n %s\n\n does not exist in the file system"));
729 tmpStr = GetSharedMessage(CANT_READ_ERROR);
731 permissionErrors = appendErrorMessage(permissionErrors, tmpStr, from);
738 if (strcmp(target_dir, "/") == 0)
740 target_file = (char *)XtMalloc(strlen(target_dir) +
741 strlen(updates[i].file) + 1);
742 sprintf(target_file, "%s%s", target_dir, updates[i].file);
746 target_file = (char *)XtMalloc(strlen(target_dir) +
747 strlen(updates[i].file) + 2);
748 sprintf(target_file, "%s/%s", target_dir, updates[i].file);
753 if (strcmp(target_dir, "/") == 0)
755 target_file = (char *)XtMalloc(strlen(target_dir) +
756 strlen(to_file) + 1);
757 sprintf(target_file, "%s%s", target_dir, to_file);
761 target_file = (char *)XtMalloc(strlen(target_dir) +
762 strlen(to_file) + 2);
763 sprintf(target_file, "%s/%s", target_dir, to_file);
766 if (updates[i].app_man_dir)
767 target_file = _DtResolveAppManPath(target_file,
768 updates[i].app_man_dir);
769 /* check if source and target files are the same.
770 * if they are the same, set a flag noting that they are. If the
771 * the operation is a move, it doesn't make any sense to move it, so
772 * send back a MOVE_TO_SAME_DIR msg.
775 if ((mode != MAKE_BUFFER) && (strcmp(target_file, from) == 0))
777 if (mode == MOVE_FILE && stat(target_file, &stat_buf) == 0)
779 if(S_ISDIR(stat_buf.st_mode))
781 pipe_msg = PIPEMSG_MOVE_TO_SAME_DIR;
782 write(pipe_s2m, &pipe_msg, sizeof(short));
783 write(pipe_s2m, &i, sizeof(int));
792 /* for copy operations, check for write permission on the target */
794 /* for move operations, check for write permission on the source and */
795 /* target directories */
796 /* the error message is appended to a list and dealt with later */
797 /* the current file is not processed */
798 if (mode == COPY_FILE)
800 if (CheckAccess(target_dir,W_OK) == -1)
804 if(CopyString == NULL)
805 CopyString = XtNewString(from);
808 CopyString = (char *) XtRealloc(CopyString,strlen(CopyString)+
810 strcat(CopyString,"\n");
811 strcat(CopyString,from);
816 else if (mode == MOVE_FILE)
818 Boolean error = FALSE;
819 if (targetChecked || CheckAccess(target_dir,W_OK) == -1)
822 if(MoveString1 == NULL)
823 MoveString1 = XtNewString(from);
826 MoveString1=(char *)XtRealloc(MoveString1,strlen(MoveString1)+
828 strcat(MoveString1,"\n");
829 strcat(MoveString1,from);
831 error = targetError = TRUE;
832 targetChecked = TRUE;
834 if (CheckAccess(_DtPName(from),W_OK) == -1)
837 if(MoveString2 == NULL)
838 MoveString2 = XtNewString(from);
841 MoveString2 = (char *)XtRealloc(MoveString2,strlen(MoveString2)+
843 strcat(MoveString2,"\n");
844 strcat(MoveString2,from);
848 if (error || targetError)
855 /* check if target file already exists */
856 if (stat(target_file, &stat_buf) == 0)
858 /* target file already exists: remember and deal with it later */
859 if(mode == MOVE_FILE && S_ISDIR(stat_buf.st_mode)
860 && DirectoryBusy(target_file))
864 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."));
866 PipeWriteErrmsg( pipe_s2m, -1, msg, target_file );
872 if (sameIndex == NULL)
874 sameIndex = (int *)XtMalloc(file_count*sizeof(int));
875 sameConfirmType = (int *)XtMalloc(file_count*sizeof(int));
877 sameIndex[sameCount] = i;
879 /* determine how to set the pipe message */
880 if (mode == MAKE_BUFFER)
882 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
886 stat(from, &from_stat_buf);
887 if ( S_ISDIR(from_stat_buf.st_mode) &&
888 S_ISDIR(stat_buf.st_mode) &&
891 /* if its a directory and there already is a directory of the
892 * same name the user may want to merge the directories into
893 * one directory. But if the directory to be copied is being
894 * copied into the same directory it came from, it doesn't make
895 * sense to merge. Set up message to REPLACE_RENAME_SAME
896 * indicating it is being copied from and to the same directory
899 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
901 sameConfirmType[sameCount] = PIPEMSG_REPLACE_MERGE;
905 /* If the copy/move/link is to the same directory, set up a
906 * different case then when the op is happening from different
910 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
912 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
914 } /* endif mode != MAKE_BUFFER */
918 if (mode != MAKE_BUFFER)
919 XtFree ((char *) from);
921 XtFree ((char *) target_file);
923 } /* endif targetfile already exists */
925 if ((isContainer = (to_file == NULL)))
931 * Note: it is important that SendModifyMsg is called before any
932 * changes are made to either the source or target directory.
933 * This is because SendModifyMsg is supposed to obtain and send
934 * the time stamp of the directories BEFORE any operation. If
935 * the wrong timestamp is sent, the window will be updated and
936 * redrawn twice instead of just once.
938 SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, i,
942 if (mode == MAKE_BUFFER)
944 /* Call CreateFileFromBuffer */
945 return_val = CreateFileFromBuffer(pipe_s2m, to,
947 updates[i].bufferInfo.buf_ptr,
948 updates[i].bufferInfo.size);
952 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
953 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
955 FileOpError, True, DESKTOP);
957 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
959 FileOpError, True, NOT_DESKTOP);
960 XtFree( (char *) from );
963 XtFree ((char *) target_file);
967 if(CopyError == TRUE)
970 errMsg = GETMESSAGE(11,48,
971 "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");
972 DisplayErrorMessage(pipe_s2m,errMsg,CopyString,target_dir);
974 permissionErrors = NULL;
978 if(MoveError1 == TRUE)
981 errMsg = GETMESSAGE(11,49,
982 "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");
983 DisplayErrorMessage(pipe_s2m,errMsg,MoveString1,target_dir);
985 permissionErrors = NULL;
989 if(MoveError2 == TRUE)
992 errMsg = GETMESSAGE(11,50,
993 "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");
994 DisplayErrorMessage(pipe_s2m,errMsg,MoveString2,target_dir);
996 permissionErrors = NULL;
1002 /* If there were any permissions errors, show the error message */
1003 if (permissionErrors != NULL)
1005 PipeWriteErrmsg(pipe_s2m, -1, permissionErrors, NULL);
1006 XtFree(permissionErrors);
1011 * Now deal with with the cases where we found that the target file
1018 * @@@ Note: The code below for sending a target-time pipe message
1019 * at this point shouldn't really be necessary.
1020 * The problem is that the target directory time stamp MUST be
1021 * obtained BEFORE any changes are made to the directory;
1022 * otherwise, the window will be updated and redrawn twice instead
1023 * of just once. Unfortunately, currently, if the user chooses to
1024 * replace or rename the existing file, the rename or delete
1025 * operation is done in the main process (inside the
1026 * replace_rename_ok_callback in Overwrite.c), instead of here in
1027 * the child process where it belongs (the main process shouldn't
1028 * do any file system operations because they could block for a
1029 * long time on a slow server). If and when overwrite dialog code
1030 * is fixed, the code below can be deleted; the target-time
1031 * message will then be sent by the call to SendModifyMsg further
1032 * below after the call to PipeRead.
1036 if (stat(target_dir, &stat_buf) == 0)
1038 modify_time = stat_buf.st_mtime;
1039 pipe_msg = PIPEMSG_TARGET_TIME;
1040 write(pipe_s2m, &pipe_msg, sizeof(short));
1041 write(pipe_s2m, &modify_time, sizeof(long));
1046 /* send message to main process to display dialog (and possibly remove/rename files) */
1047 if (file_count == 1)
1049 if (to_file == NULL) /* note target_file here is only file name, above it is full path */
1050 target_file = updates[sameIndex[0]].file;
1052 target_file = to_file;
1053 pipe_msg = sameConfirmType[0];
1054 DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
1055 write(pipe_s2m, &pipe_msg, sizeof(short));
1056 DPRINTF(("FileMoveCopyProcess: sending: mode %d directory \"%s\" file \"%s\" \n",
1057 mode, directory, target_file));
1058 write(pipe_s2m, &mode, sizeof(int));
1059 PipeWriteString(pipe_s2m, directory);
1060 PipeWriteString(pipe_s2m, target_file);
1064 int processCount=file_count-errorCount;
1066 /* If the copy/move/link is to the same directory, set up a
1067 * different case then when the op is happening from different
1071 pipe_msg = PIPEMSG_MULTICOLLIDE_SAME;
1073 pipe_msg = PIPEMSG_MULTICOLLIDE;
1075 DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
1076 write(pipe_s2m, &pipe_msg, sizeof(short));
1077 DPRINTF(("FileMoveCopyProcess: sending: mode %d processCount %d sameCount %d directory \"%s\"\n",
1078 mode, processCount, sameCount, directory));
1079 write(pipe_s2m, &mode, sizeof(int));
1080 write(pipe_s2m, &processCount, sizeof(int));
1081 write(pipe_s2m, &sameCount, sizeof(int));
1082 PipeWriteString(pipe_s2m, directory);
1083 DPRINTF(("FileMoveCopyProcess: sending %d filename strings\n", sameCount));
1084 for (i = 0; i < sameCount; i++)
1085 PipeWriteString(pipe_s2m, updates[sameIndex[i]].file);
1088 /* wait for reply from main process */
1090 PipeRead(pipe_m2s, &rc, sizeof(int));
1091 DPRINTF(("FileMoveCopyProcess: woke up after confirm, rc %d\n", rc));
1092 if (rc != PIPEMSG_CANCEL)
1094 /* affirmative reply: do the operation */
1095 for(i = 0; i < sameCount; i++)
1098 if (rc != PIPEMSG_RENAME_BUFFER)
1100 SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, j,
1104 if (rc == PIPEMSG_MULTI_PROCEED)
1107 PipeRead(pipe_m2s, &opvalue, sizeof(int));
1112 if (mode != MAKE_BUFFER)
1114 from = ResolveLocalPathName( updates[j].host,
1115 updates[j].directory,
1119 if( TT_OK != tt_status )
1121 char msg1[2*MAX_PATH];
1124 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1125 updates[j].directory, updates[j].host,
1128 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1129 updates[j].directory, updates[j].host,
1132 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
1139 if ( (isContainer = (to_file == NULL)) )
1145 to = (char *)XtMalloc(strlen(target_dir) + strlen(to_file) + 2);
1146 sprintf(to, "%s/%s", target_dir, to_file);
1151 /* check the return code for type of message and */
1152 /* perform the appropriate action */
1157 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
1158 return_val = FileManip((Widget) (intptr_t) pipe_s2m, MERGE_DIR, from,
1160 FileOpError, True, DESKTOP);
1162 return_val = FileManip((Widget) (intptr_t) pipe_s2m, MERGE_DIR, from,
1164 FileOpError, True, NOT_DESKTOP);
1167 case PIPEMSG_REPLACE_BUFFER:
1168 target_file = (char *)XtMalloc(strlen(to) + strlen(updates[j].file)
1170 sprintf(target_file, "%s/%s", to, updates[j].file);
1171 DPRINTF (("file is %s",updates[j].file));
1172 return_val = CreateFileFromBuffer(pipe_s2m,
1175 updates[j].bufferInfo.buf_ptr,
1176 updates[j].bufferInfo.size);
1177 XtFree((char *)target_file);
1180 case PIPEMSG_RENAME_BUFFER:
1182 renamed_file = PipeReadString(pipe_m2s);
1184 SendModifyMsg(pipe_s2m, mode, first_op, to, updates, j, renamed_file);
1185 target_file = (char *)XtMalloc(strlen(to) + strlen(renamed_file)
1187 sprintf(target_file, "%s/%s", to, renamed_file);
1188 DPRINTF(("file is %s",renamed_file));
1189 return_val = CreateFileFromBuffer(pipe_s2m,
1192 updates[j].bufferInfo.buf_ptr,
1193 updates[j].bufferInfo.size);
1194 XtFree((char *) target_file);
1199 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
1200 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
1201 isContainer,FileOpError, True,
1205 /* if the operation (move/copy/link) is happening from
1206 * and to the same folder, we want to create a new name
1207 * for the object for which the operation is happening
1212 char path[MAX_PATH], newDir[MAX_PATH],
1217 generate_NewPath(path,path);
1218 split_path(path, newDir, newFile);
1219 toFile = (char *)XtMalloc(strlen(newDir) +
1220 strlen(newFile) + 3);
1221 strcpy(toFile, newDir);
1222 strcat(toFile, "/");
1223 strcat(toFile, newFile);
1225 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from,
1226 toFile, False, FileOpError,
1232 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from,
1233 to, isContainer, FileOpError,
1238 if (to_file != NULL)
1240 XtFree ((char *) to);
1244 }/*end if rc != PIPEMSG_CANCEL*/
1247 XtFree((char *)sameIndex);
1249 XtFree((char *)sameConfirmType);
1250 sameConfirmType = NULL;
1252 } /* endif sameCount != 0 */
1255 pipe_msg = PIPEMSG_DONE;
1256 if (rc != PIPEMSG_CANCEL)
1257 rc = return_val? 0: -1;
1260 write(pipe_s2m, &pipe_msg, sizeof(short));
1261 write(pipe_s2m, &rc, sizeof(int));
1263 XtFree ((char *) target_dir);
1270 /*--------------------------------------------------------------------
1271 * FileMoveCopyProcessDesktop:
1272 * Main routine of the background process that handles files
1273 * dropped in desktop icons.
1274 *------------------------------------------------------------------*/
1277 FileMoveCopyProcessDesktop(
1285 DesktopRec *desktopWindow)
1289 Boolean first_op = True;
1290 Boolean return_val = False;
1292 Tt_status tt_status;
1294 /* Get the fully qualified destination path. */
1295 to = ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
1296 if( TT_OK != tt_status )
1298 char msg1[2*MAX_PATH];
1300 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1301 directory, host, host);
1303 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1304 directory, host, host);
1306 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
1307 pipe_msg = PIPEMSG_FILEOP_ERROR;
1309 write(pipe_s2m, &pipe_msg, sizeof(short));
1310 write(pipe_s2m, &rc, sizeof(int));
1313 DtEliminateDots(to);
1315 for (i = 0; i < file_count; i++)
1317 /* get full name of the source file, if just */
1318 /* dealing with regular files */
1319 if (mode != MAKE_BUFFER)
1321 from = ResolveLocalPathName(updates[i].host,
1322 updates[i].directory,
1328 char msg[2*MAX_PATH];
1331 sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1332 updates[i].directory, updates[i].host, updates[i].host);
1334 sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1335 updates[i].directory, updates[i].host, updates[i].host);
1337 PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
1339 else if (strcmp(to, from) == 0)
1341 char msg[2*MAX_PATH];
1343 sprintf(msg,GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"),to);
1344 PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
1345 XtFree ((char *) from);
1348 } /* end if dealing with regular files */
1351 SendModifyMsg(pipe_s2m, mode, first_op, to, updates, i, updates[i].file);
1355 if (mode == MAKE_BUFFER)
1359 if (strcmp(to, "/") == 0)
1361 target_file = (char *) XtMalloc(strlen(to) +
1362 strlen(updates[i].file) + 1);
1363 sprintf(target_file, "%s%s", to, updates[i].file);
1367 target_file = (char *) XtMalloc(strlen(to) +
1368 strlen(updates[i].file) + 2);
1369 sprintf(target_file, "%s/%s", to, updates[i].file);
1372 return_val = CreateFileFromBuffer(pipe_s2m,
1375 updates[i].bufferInfo.buf_ptr,
1376 updates[i].bufferInfo.size);
1380 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to, TRUE,
1381 FileOpError, True, DESKTOP);
1387 pipe_msg = PIPEMSG_DONE;
1388 rc = return_val? 0: -1;
1389 write(pipe_s2m, &pipe_msg, sizeof(short));
1390 write(pipe_s2m, &rc, sizeof(int));
1392 XtFree ((char *) to);
1398 RemoveIconFromWorkspace( char * iconName,
1401 DesktopRec *desktopWin;
1403 char fileName[MAX_PATH];
1406 for(i = 0; i < desktop_data->numIconsUsed; i++)
1408 desktopWin = desktop_data->desktopWindows[i];
1410 if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
1411 sprintf( fileName, "/%s", desktopWin->file_name );
1413 sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
1415 if( strcmp( fileName, iconName ) == 0 )
1419 Screen *currentScreen;
1421 char *workspace_name;
1423 screen = XDefaultScreen(XtDisplay(desktopWin->shell));
1425 XScreenOfDisplay(XtDisplay(desktopWin->shell), screen);
1426 rootWindow = RootWindowOfScreen(currentScreen);
1428 if(DtWsmGetCurrentWorkspace(XtDisplay(desktopWin->shell),
1429 rootWindow, &pCurrent) == Success)
1431 XGetAtomName (XtDisplay(desktopWin->shell), pCurrent);
1433 workspace_name = XtNewString("One");
1435 if( strcmp( workspace_name, desktopWin->workspace_name ) == 0 )
1437 RemoveDT( desktopWin->shell, (XtPointer) desktopWin,
1442 XtFree( desktopWin->dir_linked_to );
1443 desktopWin->dir_linked_to = XtNewString( targetDir );
1446 XtFree(workspace_name);
1452 ChangeWorkspaceIconLink( FileMgrData *fmd,
1457 DesktopRec *desktopWin;
1460 char fileName[MAX_PATH];
1463 for(i = 0; i < desktop_data->numIconsUsed; i++)
1465 desktopWin = desktop_data->desktopWindows[i];
1467 if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
1468 sprintf( fileName, "/%s", desktopWin->file_name );
1470 sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
1472 DtEliminateDots(fileName);
1473 if( strcmp( fileName, iconName ) == 0 )
1474 dirp = XtNewString(targetDir);
1475 else if(IsInParentDir(iconName,desktopWin->dir_linked_to))
1477 int index = strlen(iconPdir);
1478 char *tptr = desktopWin->dir_linked_to;
1480 dirp = XtCalloc( 1, strlen(targetDir)+ strlen(&tptr[index])+1);
1481 sprintf(dirp,"%s%s",targetDir,&tptr[index]);
1486 FileViewData *file_view_data;
1487 DirectorySet *directory_set;
1488 FileMgrData *file_mgr_data;
1489 Tt_status tt_status;
1490 char * full_dir_name;
1492 file_view_data = desktopWin->file_view_data;
1493 directory_set = (DirectorySet *)file_view_data->directory_set;
1494 file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
1497 fmd = file_mgr_data;
1498 FreeFileData( file_view_data->file_data, True );
1499 file_view_data->file_data = NULL;
1501 XtFree( desktopWin->dir_linked_to );
1502 desktopWin->dir_linked_to = XtNewString( dirp );
1503 DtEliminateDots(desktopWin->dir_linked_to);
1507 if (fmd->restricted_directory == NULL)
1508 desktopWin->restricted_directory = NULL;
1510 desktopWin->restricted_directory =
1511 XtNewString(fmd->restricted_directory);
1513 if (fmd->helpVol == NULL)
1514 desktopWin->helpVol = NULL;
1516 desktopWin->helpVol = XtNewString(fmd->helpVol);
1518 desktopWin->helpVol = XtNewString( fmd->helpVol );
1519 desktopWin->view = fmd->view;
1520 desktopWin->order = fmd->order;
1521 desktopWin->direction = fmd->direction;
1522 desktopWin->positionEnabled = fmd->positionEnabled;
1523 desktopWin->toolbox = fmd->toolbox;
1526 full_dir_name = ResolveLocalPathName(desktopWin->host,
1531 if( TT_OK == tt_status )
1533 FileData2 file_data2;
1537 DtEliminateDots (full_dir_name);
1540 IsToolBox = fmd->toolbox;
1544 if (strcmp(desktopWin->file_name, ".") == 0)
1545 ReadFileData2(&file_data2, full_dir_name, NULL, IsToolBox);
1547 ReadFileData2(&file_data2, full_dir_name, desktopWin->file_name,
1550 file_view_data->file_data = FileData2toFileData(&file_data2, &n);
1551 XtFree(full_dir_name);
1552 full_dir_name = NULL;
1555 ((DirectorySet *)file_view_data->directory_set)->name =
1558 SaveDesktopInfo(NORMAL_RESTORE);
1565 /*--------------------------------------------------------------------
1567 * Read and process data sent through the pipe.
1568 *------------------------------------------------------------------*/
1572 XtPointer client_data,
1576 FileOpCBData *cb_data = (FileOpCBData *)client_data;
1579 char *title, *err_msg, *err_arg;
1580 char *directory, *file, *target_file;
1584 int nSelected, nCollisions;
1586 static int status = 0;
1588 static ActionAreaItem replace_rename_actionItems[] = {
1589 {"Ok", 9, 27, NULL, NULL}, /* changed later based on mode */
1590 {"Cancel", 9, 28, replace_rename_cancel_callback, NULL},
1591 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_REN},
1594 ActionAreaDefn replace_renameActions = {
1595 XtNumber(replace_rename_actionItems),
1596 1, /* Cancel is default action */
1597 replace_rename_actionItems
1600 static ActionAreaItem replace_merge_actionItems[] = {
1601 {"Ok", 9, 27, replace_merge_ok_callback, NULL},
1602 {"Cancel", 9, 28, replace_merge_cancel_callback, NULL}, /* changed below depending on mode */
1603 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_MRG},
1606 ActionAreaDefn replace_mergeActions = {
1607 XtNumber(replace_merge_actionItems),
1608 1, /* Cancel is default action */
1609 replace_merge_actionItems
1612 static ActionAreaItem multicollide_actionItems[] = {
1613 {"Ok", 9, 27, NULL, NULL}, /* changed later based on Mode */
1614 {"Cancel", 9, 28, multicollide_cancel_callback, NULL}, /* changed below depending on mode */
1615 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_MULTI},
1618 ActionAreaDefn multicollideActions = {
1619 XtNumber(multicollide_actionItems),
1620 1, /* Cancel is default action */
1621 multicollide_actionItems
1625 /* Initialize Action Area structures based on mode */
1626 /* Set the appropriate callback routines */
1627 mode = cb_data->mode;
1631 replace_rename_actionItems[0].callback =
1632 buffer_replace_rename_ok_callback;
1633 multicollide_actionItems[0].callback =
1634 buffer_multicollide_ok_callback;
1637 replace_rename_actionItems[0].callback =
1638 replace_rename_ok_callback;
1639 multicollide_actionItems[0].callback =
1640 multicollide_ok_callback;
1645 /* read the next msg from the pipe */
1647 n = PipeRead(*fd, &pipe_msg, sizeof(short));
1648 DPRINTF(("FileOpPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
1653 case PIPEMSG_FILEOP_ERROR:
1654 PipeRead(*fd, &rc, sizeof(int));
1655 err_msg = PipeReadString(*fd);
1656 err_arg = PipeReadString(*fd);
1657 if (cb_data->desktop)
1658 FileOperationError(cb_data->file_view_data->widget,
1662 /* routine can be called with a NULL file_mgr_rec, use the
1663 * top level widget if this is the case.
1665 if(cb_data->file_mgr_rec)
1666 FileOperationError(cb_data->file_mgr_rec->file_window,
1669 FileOperationError(toplevel, err_msg, err_arg);
1673 if(cb_data->callback_data)
1675 RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
1676 ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
1677 ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
1679 status = PIPEMSG_FILEOP_ERROR;
1682 case PIPEMSG_CONFIRM:
1683 err_msg = PipeReadString(*fd);
1684 title = XtNewString(GETMESSAGE(9,11, "File Manager - Move/Copy/Link Warning"));
1685 filop_confirm_fd = cb_data->pipe_m2s;
1686 _DtMessageDialog(toplevel, title, err_msg, NULL, TRUE,
1687 moveCopyLinkCancel, moveCopyLinkOK, NULL,
1688 HelpRequestCB, False, QUESTION_DIALOG);
1693 case PIPEMSG_REPLACE_RENAME_SAME:
1694 /* filename collision: display replace/rename dialog */
1695 PipeRead(*fd, &mode, sizeof(int));
1696 directory = PipeReadString(*fd);
1697 file = PipeReadString(*fd);
1698 /* routine can be called with a NULL file_mgr_rec, use the
1699 * top level widget if this is the case.
1702 /* the object is copying/linking itself to the same folder. Want
1703 * to indicate the to the ok dialog and the building of the replace
1706 replace_rename_actionItems[0].data = (XtPointer)True;
1707 if(cb_data->file_mgr_rec)
1708 create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
1709 mode, directory, file,
1711 replace_renameActions, True);
1713 create_replace_rename_dialog(toplevel,
1714 mode, directory, file,
1716 replace_renameActions, True);
1721 case PIPEMSG_REPLACE_RENAME:
1722 /* filename collision: display replace/rename dialog */
1723 PipeRead(*fd, &mode, sizeof(int));
1724 directory = PipeReadString(*fd);
1725 file = PipeReadString(*fd);
1726 /* routine can be called with a NULL file_mgr_rec, use the
1727 * top level widget if this is the case.
1729 replace_rename_actionItems[0].data = (XtPointer)NULL;
1730 if(cb_data->file_mgr_rec)
1731 create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
1732 mode, directory, file,
1734 replace_renameActions, False);
1736 create_replace_rename_dialog(toplevel,
1737 mode, directory, file,
1739 replace_renameActions, False);
1744 case PIPEMSG_REPLACE_MERGE:
1745 /* filename collision: display replace/merge dialog */
1746 PipeRead(*fd, &mode, sizeof(int));
1747 directory = PipeReadString(*fd);
1748 file = PipeReadString(*fd);
1749 /* routine can be called with a NULL file_mgr_rec, use the
1750 * top level widget if this is the case.
1752 if(cb_data->file_mgr_rec)
1753 create_replace_merge_dialog(cb_data->file_mgr_rec->shell,
1754 mode, directory, file,
1756 replace_mergeActions);
1758 create_replace_merge_dialog(toplevel,
1759 mode, directory, file,
1761 replace_mergeActions);
1766 case PIPEMSG_MULTICOLLIDE_SAME:
1767 /* filename collision: display multicollide dialog */
1768 PipeRead(*fd, &mode, sizeof(int));
1769 PipeRead(*fd, &nSelected, sizeof(int));
1770 PipeRead(*fd, &nCollisions, sizeof(int));
1771 directory = PipeReadString(*fd);
1772 file = XtMalloc( MAX_PATH );
1773 fileList = (String *) XtMalloc(nCollisions * sizeof(String)); /* de- allocated in dialog's callback functions */
1774 for (i = 0; i < nCollisions; i++)
1776 fileList[i] = PipeReadString(*fd);
1778 /* routine can be called with a NULL file_mgr_rec, use the
1779 * top level widget if this is the case.
1782 /* the object is copying/linking itself to the same folder. Want
1783 * to indicate the to the ok dialog and the building of the replace
1786 multicollide_actionItems[0].data = (XtPointer)True;
1787 if(cb_data->file_mgr_rec)
1788 create_multicollide_dialog(cb_data->file_mgr_rec->shell,
1789 mode, nSelected, nCollisions,
1790 directory, fileList,
1792 multicollideActions, True);
1794 create_multicollide_dialog(toplevel,
1795 mode, nSelected, nCollisions,
1796 directory, fileList,
1798 multicollideActions, True);
1802 case PIPEMSG_MULTICOLLIDE:
1803 /* filename collision: display multicollide dialog */
1804 PipeRead(*fd, &mode, sizeof(int));
1805 PipeRead(*fd, &nSelected, sizeof(int));
1806 PipeRead(*fd, &nCollisions, sizeof(int));
1807 directory = PipeReadString(*fd);
1808 file = XtMalloc( MAX_PATH );
1809 fileList = (String *) XtMalloc(nCollisions * sizeof(String)); /* de-allocated in dialog's callback functions */
1810 for (i = 0; i < nCollisions; i++)
1812 fileList[i] = PipeReadString(*fd);
1814 /* routine can be called with a NULL file_mgr_rec, use the
1815 * top level widget if this is the case.
1817 multicollide_actionItems[0].data = (XtPointer)NULL;
1818 if(cb_data->file_mgr_rec)
1819 create_multicollide_dialog(cb_data->file_mgr_rec->shell,
1820 mode, nSelected, nCollisions,
1821 directory, fileList,
1823 multicollideActions, False);
1825 create_multicollide_dialog(toplevel,
1826 mode, nSelected, nCollisions,
1827 directory, fileList,
1829 multicollideActions, False);
1834 case PIPEMSG_TARGET_TIME:
1835 /* get the modify time and update the directory cache */
1836 PipeRead(*fd, &modify_time, sizeof(long));
1837 DirectoryModifyTime(cb_data->host, cb_data->directory, modify_time);
1840 case PIPEMSG_MOVE_TO_SAME_DIR:
1841 /* get the update index */
1842 PipeRead(*fd, &i, sizeof(int));
1843 cb_data->updates[i].operationStatus = True;
1844 DisplayDuplicateOpError((void *) cb_data,i);
1845 status = PIPEMSG_MOVE_TO_SAME_DIR;
1846 if(cb_data->callback_data)
1848 RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
1849 ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
1850 ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
1854 case PIPEMSG_FILE_MODIFIED:
1855 /* get the update index and modify time */
1856 PipeRead(*fd, &i, sizeof(int));
1857 PipeRead(*fd, &modify_time, sizeof(long));
1858 target_file = PipeReadString(*fd);
1859 DPRINTF (("PIPEMSG_FILE_MODIFIED %s\n", target_file));
1861 /* mark the file updated in the cached target directory */
1862 DirectoryFileModified(cb_data->host, cb_data->directory,
1865 if (cb_data->mode == MOVE_FILE)
1867 /* mark the file updated in the cached source directory */
1868 if (modify_time != 0)
1869 DirectoryModifyTime(cb_data->updates[i].host,
1870 cb_data->updates[i].directory,
1872 DirectoryFileModified(cb_data->updates[i].host,
1873 cb_data->updates[i].directory,
1874 cb_data->updates[i].file);
1876 cb_data->updates[i].operationStatus = True;
1877 XtFree(target_file); target_file = NULL;
1881 PipeRead(*fd, &rc, sizeof(int));
1886 fprintf(stderr, "Internal error in FileOpPipeCB: bad pipe_msg %d\n",
1894 char tmpDir[MAX_PATH];
1896 DPRINTF(("FileOpPipeCB: done, rc %d\n", rc));
1898 /* close the pipe and cancel the callback */
1899 close(cb_data->pipe_m2s);
1900 close(cb_data->pipe_s2m);
1904 *fd = (rc == 0)? 0: -1;
1906 /* arrange for modified directories to be updated */
1907 DirectoryEndModify(cb_data->host, cb_data->directory);
1909 /* Reposition the objects which have been modified */
1910 if(!cb_data->finish_callback && cb_data->file_mgr_data)
1914 /* Do this only if it is the current directory and Random placement
1916 if(cb_data->file_mgr_data->positionEnabled != RANDOM_OFF && strcmp(
1917 cb_data->directory,cb_data->file_mgr_data->current_directory)==0)
1919 file_set = (char **) XtCalloc(1,cb_data->file_count*sizeof(char *));
1920 for(i=0;i<cb_data->file_count;i++)
1922 if(cb_data->updates[i].operationStatus == True)
1923 file_set[actual_count++] = cb_data->updates[i].file;
1925 RepositionIcons(cb_data->file_mgr_data, file_set,actual_count,
1926 G_dropx, G_dropy, True);
1927 XtFree((char *)file_set);
1932 for(i = 0; i < desktop_data->numWorkspaces; i++)
1933 DeselectAllDTFiles(desktop_data->workspaceData[i]);
1935 for (i = 0; i < cb_data->file_count; i++)
1937 char fileName[MAX_PATH];
1939 /* Scroll the window to show the created object, since we
1940 cannot keep scrolling for each object we just do it for
1941 one object and we do it in case of Drag/Drop, but not
1942 for Select.MoveTo/CopyTo ... */
1944 if(!i && cb_data->callback_data == NULL)
1948 if(cb_data && cb_data->file_mgr_data)
1950 fmd = cb_data->file_mgr_data;
1951 fmd->scrollToThisDirectory = XtNewString(cb_data->directory);
1952 fmd->scrollToThisFile = XtNewString(cb_data->updates[i].file);
1955 if (cb_data->updates[i].first_index == i)
1957 if (cb_data->mode == MOVE_FILE)
1959 DirectoryEndModify(cb_data->updates[i].host,
1960 cb_data->updates[i].directory);
1961 if( strcmp( cb_data->updates[i].directory, "/" ) == 0 )
1964 sprintf( tmpDir, "%s", cb_data->updates[i].directory );
1967 if( cb_data->updates[i].host )
1968 XtFree( cb_data->updates[i].host );
1969 if( cb_data->updates[i].directory )
1970 XtFree( cb_data->updates[i].directory );
1971 if( cb_data->updates[i].app_man_dir )
1972 XtFree( cb_data->updates[i].app_man_dir );
1975 if( cb_data->mode == MOVE_FILE )
1977 sprintf( fileName, "%s/%s", tmpDir, cb_data->updates[i].file );
1978 if( cb_data->updates[i].operationStatus == True )
1980 if( status == PIPEMSG_MOVE_TO_SAME_DIR )
1982 RemoveIconFromWorkspace( fileName, cb_data->directory );
1984 else if( status != PIPEMSG_FILEOP_ERROR )
1986 ChangeWorkspaceIconLink(cb_data->file_mgr_data, fileName,
1987 cb_data->directory,tmpDir );
1989 /* If it is workspace drag and drop and the move operation
1990 is not because of Select.MoveTo menu option */
1992 if(initiating_view == NULL && cb_data->callback_data == NULL)
1994 sprintf( fileName, "%s/%s", cb_data->directory,
1995 cb_data->updates[i].file );
1996 DtEliminateDots(fileName);
1997 RemoveIconFromWorkspace( fileName, cb_data->directory );
2003 XtFree(cb_data->updates[i].file);
2008 /* call the callback routine */
2009 if (cb_data->finish_callback)
2010 (*cb_data->finish_callback)(cb_data->callback_data, rc);
2012 /* free the callback data */
2013 XtFree((char *)cb_data->updates);
2014 XtFree((char *)cb_data->directory);
2015 XtFree((char *)cb_data->host);
2016 XtFree(client_data);
2021 /*--------------------------------------------------------------------
2023 * Start the background process and set up callback for the pipe.
2024 *------------------------------------------------------------------*/
2034 BufferInfo *buffer_set,
2036 unsigned int modifiers,
2037 DesktopRec *desktopWindow,
2038 void (*finish_callback)(),
2039 XtPointer callback_data)
2041 static char *pname = "_FileMoveCopy";
2043 FileOpCBData *cb_data;
2047 char *source_dir = NULL;
2048 char *source_file = NULL;
2054 struct timeval now, select_end, select_timeout;
2055 Boolean operation_done;
2059 /* Determine the type of operation: move, copy, or link */
2060 /* or creating buffers */
2061 if (buffer_set != NULL)
2067 modifiers &= ~Button2Mask;
2068 if (modifiers == ShiftMask)
2070 else if (modifiers == ControlMask)
2076 /* set up the callback data structure */
2077 cb_data = XtNew(FileOpCBData);
2078 cb_data->desktop = (desktopWindow != NULL);
2079 if (cb_data->desktop)
2081 cb_data->file_mgr_data = NULL;
2082 cb_data->file_mgr_rec = NULL;
2083 cb_data->file_view_data = (FileViewData *)data;
2084 cb_data->desktopWindow = desktopWindow;
2090 cb_data->file_mgr_data = (FileMgrData *)data;
2091 cb_data->file_mgr_rec =
2092 (FileMgrRec *) ((FileMgrData *)data)->file_mgr_rec;
2096 cb_data->file_mgr_data = NULL;
2097 cb_data->file_mgr_rec = NULL;
2099 cb_data->file_view_data = NULL;
2100 cb_data->desktopWindow = NULL;
2102 cb_data->mode = mode;
2103 cb_data->host = XtNewString(host);
2104 cb_data->directory = XtNewString(directory);
2105 cb_data->finish_callback = finish_callback;
2106 cb_data->callback_data = callback_data;
2109 /* mark the target directory as being modified in the directory cache */
2110 DirectoryBeginModify(host, directory);
2112 /* make a list of the operations to be done */
2113 /* Allocate memory for the DirUpdateStructure */
2114 cb_data->file_count = file_count;
2116 updates = (DirUpdate *)XtMalloc(file_count * sizeof(DirUpdate));
2118 /* Determine whether we are dealing with files or buffers */
2119 /* This affects how the updates structure is initialized */
2120 if (mode == MAKE_BUFFER)
2122 for (i=0; i< file_count; i++)
2124 /* just simply set the the updates structure with */
2125 /* the passed in file names */
2126 updates[i].file = XtNewString(file_set[i]);
2127 updates[i].bufferInfo.buf_ptr = buffer_set[i].buf_ptr;
2128 updates[i].bufferInfo.size = buffer_set[i].size;
2130 /* set unused updates fields to NOOP values */
2131 updates[i].time_sent = FALSE;
2132 updates[i].first_index = 0;
2133 updates[i].host = NULL;
2134 updates[i].directory = NULL;
2135 updates[i].app_man_dir = NULL;
2140 /* Seperate file names, directories, and hosts */
2141 /* when dealing with real files */
2142 for (i=0; i< file_count; i++)
2144 /* get the name of the source directory */
2145 ptr = strrchr(file_set[i], '/');
2148 if (ptr == file_set[i])
2153 source_dir = file_set[i];
2155 source_file = ptr + 1;
2159 source_dir = strdup(".");
2160 source_file = file_set[i];
2163 /* see if this directory is already in the list */
2164 for (j = 0; j < i; j++)
2165 if (strcmp(updates[j].host, host_set[i]) == 0 &&
2166 strcmp(updates[j].directory, source_dir) == 0)
2170 { /* already in the list */
2171 updates[i].host = updates[j].host;
2172 updates[i].directory = updates[j].directory;
2173 updates[i].app_man_dir = updates[j].app_man_dir;
2176 { /* not yet in the list */
2177 updates[i].host = XtNewString(host_set[i]);
2178 updates[i].directory = XtNewString(source_dir);
2179 updates[i].app_man_dir = NULL;
2184 if (((FileMgrData *)data)->toolbox)
2185 updates[i].app_man_dir =
2186 XtNewString(((FileMgrData *)data)->restricted_directory);
2190 /* mark the directory as being modified in the directory cache */
2191 if (mode == MOVE_FILE)
2192 DirectoryBeginModify(updates[i].host, updates[i].directory);
2194 updates[i].first_index = j;
2195 updates[i].time_sent = False;
2196 updates[i].operationStatus = False;
2197 updates[i].file = XtNewString(source_file);
2199 if (NULL != ptr) *ptr = '/';
2208 /* fork the process that does the actual work */
2212 DirectoryAbortModify(host, directory);
2213 for (i=0; i<file_count; i++)
2214 if (mode == MOVE_FILE && updates[i].first_index == i)
2215 DirectoryAbortModify(updates[i].host, updates[i].directory);
2218 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
2219 pname, getppid(), getpid(), errno, strerror(errno));
2225 DBGFORK(("%s: child forked, m2s %d s2m %d\n",
2226 pname, pipe_m2s[0], pipe_s2m[1]));
2228 close(pipe_m2s[1]); /* won't write to pipe_m2s */
2229 close(pipe_s2m[0]); /* won't read from pipe_s2m */
2231 if (desktopWindow != NULL)
2232 rc = FileMoveCopyProcessDesktop(pipe_s2m[1], pipe_m2s[0],
2233 directory, host, updates, file_count,
2234 mode, desktopWindow);
2236 rc = FileMoveCopyProcess(pipe_s2m[1], pipe_m2s[0], to_file, directory,
2237 host, updates, file_count, mode, NULL);
2239 DBGFORK(("%s: child exiting\n", pname));
2243 DBGFORK(("%s: forked child<%d>, m2s %d, s2m %d\n",
2244 pname, pid, pipe_m2s[1], pipe_s2m[0]));
2247 /* parent: set up callback to get the pipe data */
2248 close(pipe_m2s[0]); /* won't read from pipe_m2s */
2249 close(pipe_s2m[1]); /* won't write to pipe_s2m */
2251 cb_data->pipe_m2s = pipe_m2s[1];
2252 cb_data->pipe_s2m = pipe_s2m[0];
2253 cb_data->mode = mode;
2255 cb_data->child = pid;
2259 * We wait a certain amount of time for the background process to finish.
2260 * If it doesn't finish within that time, we do the rest asynchronously.
2263 /* set up fd set for select */
2264 FD_ZERO(&select_fds);
2267 /* compute until what time we want to wait */
2268 gettimeofday(&select_end, NULL);
2269 select_end.tv_sec += FILE_MOVE_COPY_WAIT_TIME;
2271 operation_done = False;
2274 /* determine how much time is left */
2275 gettimeofday(&now, NULL);
2276 select_timeout.tv_sec = select_end.tv_sec - now.tv_sec;
2277 select_timeout.tv_usec = select_end.tv_usec - now.tv_usec;
2278 if (select_timeout.tv_usec < 0)
2280 select_timeout.tv_sec--;
2281 select_timeout.tv_usec += 1000000;
2284 if ((int) select_timeout.tv_sec < 0)
2286 /* check if our time is up */
2287 DPRINTF(("FileMoveCopy: timed out; adding input callback\n"));
2288 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
2289 pipe_s2m[0], (XtPointer)XtInputReadMask,
2290 FileOpPipeCB, (XtPointer)cb_data);
2295 FD_SET(fd, &select_fds);
2296 #if defined(__hpux) && (OSMAJORVERSION <= 10) && (OSMINORVERSION < 2)
2297 rc = select(fd + 1, (int *)&select_fds, NULL, NULL, &select_timeout);
2299 rc = select(fd + 1, &select_fds, NULL, NULL, &select_timeout);
2301 if (rc < 0 && errno != EINTR)
2303 perror("select failed in FileMoveCopy");
2308 /* call FileOpPipeCB to read & process the data from the pipe */
2309 FileOpPipeCB((XtPointer)cb_data, &fd, NULL);
2310 DPRINTF(("FileMoveCopy: FileOpPipeCB -> fd = %d\n", fd));
2313 * If the background process is done, FileOpPipeCB sets fd
2314 * to zero (in case of success) or -1 (in case of failure).
2318 operation_done = (fd == 0);
2324 return operation_done;
2328 /*--------------------------------------------------------------------
2329 * FileMoveCopy, FileMoveCopyDesktop
2330 * External entry points for invoking _FileMoveCopy
2331 *------------------------------------------------------------------*/
2335 FileMgrData *file_mgr_data,
2342 unsigned int modifiers,
2343 void (*finish_callback)(),
2344 XtPointer callback_data)
2346 return _FileMoveCopy( (XtPointer)file_mgr_data, to_file, directory, host,
2347 host_set, file_set, NULL, file_count, modifiers, NULL,
2348 finish_callback, callback_data);
2353 FileMoveCopyDesktop(
2354 FileViewData *file_view_data,
2359 unsigned int modifiers,
2360 DesktopRec *desktopWindow,
2361 void (*finish_callback)(),
2362 XtPointer callback_data)
2364 return _FileMoveCopy ((XtPointer)file_view_data,
2379 /*====================================================================
2382 * Run a background process to rename an object.
2384 *==================================================================*/
2386 /*--------------------------------------------------------------------
2387 * ChangeIconNameProcess:
2388 * Main routine of the background process
2389 *------------------------------------------------------------------*/
2392 ChangeIconNameProcess(
2395 char *directory_name,
2399 char * full_name, * old_full_name, *dir_path;
2400 struct stat stat_buf;
2405 Tt_status tt_status;
2407 /* Check for uniqueness */
2408 full_name = ResolveLocalPathName(host_name, directory_name, new_name, home_host_name, &tt_status);
2409 if ( TT_OK != tt_status )
2411 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2412 pipe_msg = PIPEMSG_FILEOP_ERROR;
2413 write(pipe_fd, &pipe_msg, sizeof(short));
2418 if (lstat(full_name, &stat_buf) == 0)
2420 /* Name is not unique */
2421 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2422 pipe_msg = PIPEMSG_EXIST_ERROR;
2423 write(pipe_fd, &pipe_msg, sizeof(short));
2430 /* send a modified message back through the pipe */
2432 dir_path = ResolveLocalPathName(host_name, directory_name, NULL, home_host_name, &tt_status);
2433 if( TT_OK != tt_status )
2435 DPRINTF(("ChadengeIconNameProcess: sending exist error\n"));
2436 pipe_msg = PIPEMSG_FILEOP_ERROR;
2437 write(pipe_fd, &pipe_msg, sizeof(short));
2443 if (stat(dir_path, &stat_buf) == 0)
2444 modify_time = stat_buf.st_mtime;
2447 /* rename the file */
2448 old_full_name = ResolveLocalPathName(host_name, directory_name, old_name, home_host_name, &tt_status);
2449 if( TT_OK != tt_status )
2451 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2452 pipe_msg = PIPEMSG_FILEOP_ERROR;
2453 write(pipe_fd, &pipe_msg, sizeof(short));
2458 success = FileManip((Widget) (intptr_t) pipe_fd, MOVE_FILE, old_full_name, full_name, TRUE,
2459 FileOpError, True, NOT_DESKTOP);
2460 XtFree( old_full_name );
2461 /* send a 'done' msg through the pipe */
2462 rc = success? 0: -1;
2465 pipe_msg = PIPEMSG_FILE_MODIFIED;
2466 write(pipe_fd, &pipe_msg, sizeof(short));
2467 write(pipe_fd, &modify_time, sizeof(long));
2469 DPRINTF(("ChangeIconNameProcess: sending DONE, rc %d\n", rc));
2470 pipe_msg = PIPEMSG_DONE;
2471 write(pipe_fd, &pipe_msg, sizeof(short));
2472 write(pipe_fd, &rc, sizeof(int));
2474 PipeWriteString(pipe_fd, full_name);
2475 XtFree( full_name );
2480 /*--------------------------------------------------------------------
2482 * Read and process data sent through the pipe.
2483 *------------------------------------------------------------------*/
2487 XtPointer client_data,
2491 ChangeIconCBData *cb_data = (ChangeIconCBData *)client_data;
2492 FileViewData *file_view_data = cb_data->file_view_data;
2493 DesktopRec *desktopWindow = cb_data->desktopWindow;
2496 DirectorySet *directory_set;
2497 FileMgrData *file_mgr_data = NULL;
2498 FileMgrRec *file_mgr_rec;
2502 char *title, *err_msg, *err_arg;
2508 Boolean desktop_changed;
2510 /* get widget for error messages */
2511 if (cb_data->desktop)
2513 msg_widget = XtParent(cb_data->w);
2517 directory_set = (DirectorySet *)file_view_data->directory_set;
2518 file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
2519 file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
2520 msg_widget = file_mgr_rec->file_window;
2523 /* read the msg from the pipe */
2525 n = PipeRead(*fd, &pipe_msg, sizeof(short));
2526 DPRINTF(("ChangeIconPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
2528 if (pipe_msg == PIPEMSG_FILE_MODIFIED)
2530 /* get modify time */
2531 PipeRead(*fd, &modify_time, sizeof(long));
2533 /* mark the old & new files as modified in the directory cache */
2534 if (modify_time != 0)
2535 DirectoryModifyTime(cb_data->host_name, cb_data->directory_name,
2537 DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
2539 DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
2544 if (pipe_msg == PIPEMSG_EXIST_ERROR)
2546 /* Name is not unique */
2547 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2548 if (cb_data->desktop)
2550 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.");
2551 err_msg = XtNewString(tmpStr);
2554 err_msg = XtNewString(GETMESSAGE(9,9, "A file with this name already exists.\nPlease choose a different name."));
2556 _DtMessage (msg_widget, title, err_msg, NULL, HelpRequestCB);
2561 else if (pipe_msg == PIPEMSG_FILEOP_ERROR)
2563 /* the rename failed */
2564 PipeRead(*fd, &rc, sizeof(int));
2565 err_msg = PipeReadString(*fd);
2566 err_arg = PipeReadString(*fd);
2567 FileOperationError(msg_widget, err_msg, err_arg);
2572 else if (pipe_msg == PIPEMSG_DONE)
2574 /* get the return code */
2575 PipeRead(*fd, &rc, sizeof(int));
2578 /* the rename was successful */
2579 full_name = PipeReadString(*fd);
2581 /* All went well, destroy the text field */
2582 XtUnmanageChild(cb_data->w);
2583 XtDestroyWidget(cb_data->w);
2585 /* Force the icon label to be updated immediately */
2586 if (cb_data->desktop)
2588 XmProcessTraversal(desktopWindow->iconGadget, XmTRAVERSE_CURRENT);
2589 desktopWindow->text = NULL;
2590 /* we'll catch this icon label in the loop after the else */
2594 file_mgr_data->renaming = NULL;
2596 label = XmStringCreateLocalized(cb_data->new_name);
2597 XtSetArg(args[0], XmNstring, label);
2598 XtSetValues(file_view_data->widget, args, 1);
2599 XmStringFree(label);
2600 XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
2601 XmUpdateDisplay (file_mgr_rec->file_window);
2604 * To prevent the positional data from becoming disassociated with
2605 * this file, we need to change the name in the positional data
2608 for (i = 0; i < file_mgr_data->num_objects; i++)
2610 if (strcmp(cb_data->old_name,
2611 file_mgr_data->object_positions[i]->name) == 0)
2614 XtFree(file_mgr_data->object_positions[i]->name);
2615 file_mgr_data->object_positions[i]->name =
2616 XtNewString(cb_data->new_name);
2623 * Check all desktop windows to see if they were linked to
2624 * the file we just renamed. If so, we need to change the
2625 * link in .dt/Desktop that points to it.
2627 * Note: We could do this in a background process, but we assume
2628 * that .dt/Desktop is local or, if it's remote and the remote server
2629 * is down, the user is screwed anyway. So we assume it's ok to do
2630 * blocking operations on .dt/Desktop in the main process.
2631 * Hence we go for the simpler solution here.
2633 desktop_changed = False;
2634 for (i = 0; i < desktop_data->numIconsUsed; i++)
2636 desktopWindow = desktop_data->desktopWindows[i];
2638 if (strcmp(cb_data->host_name, desktopWindow->host) == 0 &&
2639 strcmp(cb_data->directory_name, desktopWindow->dir_linked_to) == 0
2640 && strcmp(cb_data->old_name, desktopWindow->file_name) == 0)
2644 /* Force the icon label to be updated immediately */
2645 label = XmStringCreateLocalized(cb_data->new_name);
2646 XtSetArg(args[0], XmNstring, label);
2647 XtSetValues(desktopWindow->iconGadget, args, 1);
2648 XmStringFree(label);
2650 XtFree(desktopWindow->file_name);
2651 desktopWindow->file_name = XtNewString(cb_data->new_name);
2653 XtFree(desktopWindow->file_view_data->file_data->file_name);
2654 desktopWindow->file_view_data->file_data->file_name =
2655 XtNewString(cb_data->new_name);
2656 if( strcmp( desktopWindow->title, cb_data->old_name ) == 0 )
2658 XtFree( desktopWindow->title );
2659 desktopWindow->title = XtNewString( cb_data->new_name );
2662 GenerateShape(desktopWindow);
2664 RegisterIconDropsDT(desktopWindow);
2665 XmUpdateDisplay (desktopWindow->iconGadget);
2667 desktop_changed = True;
2671 if (desktop_changed)
2673 SaveDesktopInfo(NORMAL_RESTORE);
2681 fprintf(stderr, "Internal error in ChangeIconPipeCB: bad pipe_msg %d\n",
2684 /* arrange for the modified directory to be updated */
2685 DirectoryEndModify(cb_data->host_name, cb_data->directory_name);
2687 /* close the pipe and cancel the callback */
2691 /* free callback data */
2692 XtFree(cb_data->host_name);
2693 XtFree(cb_data->directory_name);
2694 XtFree(cb_data->old_name);
2695 XtFree(cb_data->new_name);
2696 XtFree((char *)cb_data);
2700 /*--------------------------------------------------------------------
2702 * Start the background process and set up callback for the pipe.
2703 *------------------------------------------------------------------*/
2709 FileViewData *file_view_data,
2710 DesktopRec *desktopWindow,
2712 char *directory_name)
2714 static char *pname = "_ChangeIconName";
2715 ChangeIconCBData *cb_data;
2727 int dirNameLength = strlen (directory_name);
2728 int maxFileNameLength = pathconf (directory_name, _PC_NAME_MAX);
2732 /* get the new name */
2733 XtSetArg(args[0], XmNvalue, &input_name);
2734 XtSetArg(args[1], XmNuserData, &old_name);
2735 XtGetValues(w, args, 2);
2737 new_name = (char *)_DtStripSpaces(XtNewString(input_name));
2738 length = strlen (new_name);
2741 /* new name must be a simple name, no path */
2743 if (DtStrchr (new_name, '/') != NULL)
2744 msg = XtNewString(GetSharedMessage(LOCAL_RENAME_ONLY_ERROR));
2745 #ifdef _CHECK_FOR_SPACES
2746 else if (DtStrchr (new_name, ' ') != NULL ||
2747 DtStrchr (new_name, '\t') != NULL)
2749 msg = XtNewString(GetSharedMessage(NO_SPACES_ALLOWED_ERROR));
2752 else if (length == 0 || strcmp(new_name, old_name) == 0)
2754 /* Noop; simply remove the text field */
2755 XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
2759 UnpostDTTextField();
2763 DirectorySet *directory_set =
2764 (DirectorySet *)file_view_data->directory_set;
2765 FileMgrData *file_mgr_data =
2766 (FileMgrData *)directory_set->file_mgr_data;
2767 FileMgrRec *file_mgr_rec =
2768 (FileMgrRec *)file_mgr_data->file_mgr_rec;
2769 file_mgr_rec->menuStates |= RENAME;
2770 UnpostTextField( file_mgr_data );
2771 file_mgr_data->renaming = NULL;
2775 /* Ensure the new name has length less than or equal to the maximum
2776 length that the system allows.
2777 If maxFileNameLength == -1 the file system is not supporting POSIX, use MAXNAMLEN
2779 else if( maxFileNameLength < -1 || ( maxFileNameLength == -1 && ( length > MAXNAMLEN || length + dirNameLength > MAX_PATH ) ) || ( maxFileNameLength > 0 && length > maxFileNameLength ) )
2781 msg = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2787 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2788 _DtMessage (XtParent (w), title, msg, NULL, HelpRequestCB);
2795 /* Check to see if the file has a representitive on the Desktop. */
2796 if (desktopWindow == NULL)
2798 for (i = 0; i < desktop_data->numIconsUsed; i++)
2800 if (strcmp(host_name,
2801 desktop_data->desktopWindows[i]->host) == 0 &&
2802 strcmp(directory_name,
2803 desktop_data->desktopWindows[i]->dir_linked_to) == 0 &&
2804 strcmp(old_name, desktop_data->desktopWindows[i]->
2805 file_view_data->file_data->file_name) == 0)
2807 desktopWindow = desktop_data->desktopWindows[i];
2813 if (desktopWindow != NULL)
2816 * There is a representation of this file on the desktop:
2817 * check if the there are any objects which match the new_name
2819 for (j = 0; j < desktop_data->numIconsUsed; j++)
2821 if (strcmp(new_name, desktop_data->desktopWindows[j]->
2822 file_view_data->file_data->file_name) == 0)
2824 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2826 tmpStr = GETMESSAGE(28,9, "An object with this name already exists on the Workspace.\nPlease choose a different name.");
2828 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.");
2829 msg = XtNewString(tmpStr);
2830 _DtMessage(XtParent (w), title, msg, NULL, HelpRequestCB);
2840 * Now we are ready to start the background process
2841 * that does the actual rename.
2844 /* set up callback data */
2845 cb_data = XtNew(ChangeIconCBData);
2847 cb_data->desktop = desktop;
2848 cb_data->file_view_data = file_view_data;
2849 cb_data->desktopWindow = desktopWindow;
2850 cb_data->host_name = XtNewString(host_name);
2851 cb_data->directory_name = XtNewString(directory_name);
2852 cb_data->old_name = XtNewString(old_name);
2853 cb_data->new_name = new_name;
2855 /* mark the directory as being modified in the directory cache */
2856 DirectoryBeginModify(host_name, directory_name);
2861 /* fork the process that does the actual work */
2865 DirectoryAbortModify(host_name, directory_name);
2867 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
2868 pname, getppid(), getpid(), errno, strerror(errno));
2874 DBGFORK(("%s: child forked, pipe %d\n", pname, pipe_fd[1]));
2876 close(pipe_fd[0]); /* child won't read from the pipe */
2878 rc = ChangeIconNameProcess(pipe_fd[1], host_name, directory_name,
2879 old_name, new_name);
2882 DBGFORK(("%s: child exiting\n", pname));
2887 DBGFORK(("%s: forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
2890 /* parent: set up callback to get the pipe data */
2891 close(pipe_fd[1]); /* parent won't write the pipe */
2893 cb_data->child = pid;
2895 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
2896 pipe_fd[0], (XtPointer)XtInputReadMask,
2897 ChangeIconPipeCB, (XtPointer)cb_data);
2904 XtPointer client_data,
2905 XmTextVerifyCallbackStruct * call_data)
2907 int value, size, increment, page;
2909 FileMgrData *file_mgr_data = (FileMgrData *)client_data;
2910 FileMgrRec *file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
2911 DirectorySet *directory_set = (DirectorySet *)(file_mgr_data->renaming->directory_set);
2913 if (call_data->reason == XmCR_MODIFYING_TEXT_VALUE ||
2914 call_data->reason == XmCR_MOVING_INSERT_CURSOR )
2917 /* x1 - x value of the text widget with respect to scroll window
2918 x2,y2 - x,y values of the cursor position (new) w.r.t text widget
2919 x3,y3 - x,y values of the cursor position (previous) w.r.t textW
2921 Position x1,x2,y2,x3,y3;
2922 /* width of the text widget */
2923 Dimension stringWidth;
2925 XtSetArg(args[0],XmNx,&x1);
2926 XtGetValues(w,args,1);
2928 if(XtIsManaged(file_mgr_rec->vertical_scroll_bar))
2929 SWwidth=(file_mgr_rec->scroll_window->core.width -
2930 file_mgr_rec->vertical_scroll_bar->core.width);
2932 SWwidth=file_mgr_rec->scroll_window->core.width;
2934 XmTextFieldPosToXY(w,call_data->newInsert,&x2,&y2);
2935 XmTextFieldPosToXY(w,call_data->currInsert,&x3,&y3);
2937 XtSetArg(args[0],XmNwidth,&stringWidth);
2938 XtGetValues(w,args,1);
2940 printf("\n x2=%d x1=%d x3=%d\n",x2,x1,x3);
2942 if ( (Dimension)(call_data->newInsert) < stringWidth )
2944 if( XtIsManaged(file_mgr_rec->horizontal_scroll_bar) )
2946 XmScrollBarGetValues( file_mgr_rec->horizontal_scroll_bar,
2947 &value, &size, &increment, &page);
2949 printf("\n value = %d",value);
2951 /* case where cursor is moved forward */
2955 XtSetArg (args[0], XmNmaximum, &max);
2956 XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
2957 if( (value < (max-size)) &&
2958 ((x1+x2) - value > 0 ) &&
2959 ( (Position)(((x1+x2) - value) +
2960 file_mgr_rec->vertical_scroll_bar->core.width) > (Position) SWwidth ) )
2962 if( (value+(x2-x3)) > (max-size) )
2966 XmScrollBarSetValues(
2967 file_mgr_rec->horizontal_scroll_bar,
2968 value, size, increment, page,True
2972 /* case where cursor is moved in reverse direction */
2973 else if( (x2-x3) < 0 )
2976 XtSetArg (args[0], XmNminimum, &min);
2977 XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
2978 if( (value > min) && ((Position)(x1+x3) < (Position)(value+
2979 file_mgr_rec->vertical_scroll_bar->core.width)) )
2981 if( (x2 <= 0) || ((value - (x3-x2)) < min) )
2985 XmScrollBarSetValues(file_mgr_rec->horizontal_scroll_bar,
2986 value, size, increment, page,True
2994 _ChangeIconName (w, False, file_mgr_data->renaming, NULL,
2995 file_mgr_data->host, directory_set->name);
3002 XtPointer client_data,
3003 XtPointer call_data)
3005 DesktopRec * desktopWindow = (DesktopRec *)client_data;
3007 _ChangeIconName (w, True, desktopWindow->file_view_data, desktopWindow,
3008 desktopWindow->host, desktopWindow->dir_linked_to);
3012 /*====================================================================
3015 * Run a background process to create a file or directory.
3017 *==================================================================*/
3019 /*--------------------------------------------------------------------
3021 * Build a host, directory, and file name path to be used as the
3022 * destination of a create, copy or move operation.
3023 *------------------------------------------------------------------*/
3036 strcpy(to_host, from_host);
3038 if (strncmp (new_name, "/", 1) == 0)
3040 strcpy(to_dir, new_name);
3044 if (strcmp(to_dir, "/") == 0)
3045 sprintf(to_dir, "%s%s", from_dir, new_name);
3047 sprintf(to_dir, "%s/%s", from_dir, new_name);
3050 ptr = strrchr(to_dir, '/');
3052 strcpy(to_file, ptr + 1);
3056 /*--------------------------------------------------------------------
3058 * Main routine of background process for MakeFile
3059 *------------------------------------------------------------------*/
3070 struct stat stat_buf;
3076 Tt_status tt_status;
3078 /* assume success */
3081 /* get the full name of the file/dir to be created */
3082 to = ResolveLocalPathName(to_host, to_dir, to_file, home_host_name, &tt_status);
3086 /* check if a file/dir with the same name already exists */
3087 else if (lstat (to, &stat_buf) == 0)
3090 /* now create the file/dir */
3093 /* send a modified message back through the pipe */
3095 dir_path = ResolveLocalPathName(to_host, to_dir, NULL, home_host_name, &tt_status);
3096 if (stat(dir_path, &stat_buf) == 0)
3097 modify_time = stat_buf.st_mtime;
3100 pipe_msg = PIPEMSG_FILE_MODIFIED;
3101 write(pipe_fd, &pipe_msg, sizeof(short));
3102 write(pipe_fd, &modify_time, sizeof(long));
3105 if (type == DtDIRECTORY)
3107 if (mkdir (to, (int) DtFILE_DIR_CREATION_MASK) != 0)
3115 mode = DtFILE_DATA_CREATION_MASK;
3117 mode = DtFILE_OTHER_CREATION_MASK;
3119 if ((fnew = creat(to, (int) mode)) < 0)
3126 /* send a 'done' msg through the pipe */
3127 pipe_msg = PIPEMSG_DONE;
3128 DPRINTF(("MakeFileProcess: sending DONE, rc %d\n", rc));
3129 write(pipe_fd, &pipe_msg, sizeof(short));
3130 write(pipe_fd, &rc, sizeof(int));
3131 PipeWriteString(pipe_fd, to);
3139 /*--------------------------------------------------------------------
3141 * Read and process data sent through the pipe.
3142 *------------------------------------------------------------------*/
3146 XtPointer client_data,
3150 MakeFileCBData *cb_data = (MakeFileCBData *)client_data;
3157 /* read the msg from the pipe */
3159 n = PipeRead(*fd, &pipe_msg, sizeof(short));
3161 if (pipe_msg == PIPEMSG_FILE_MODIFIED)
3163 /* get modify time */
3164 PipeRead(*fd, &modify_time, sizeof(long));
3166 /* mark the file updated in the directory cache */
3167 if (modify_time != 0)
3168 DirectoryModifyTime(cb_data->to_host, cb_data->to_dir, modify_time);
3169 DirectoryFileModified(cb_data->to_host, cb_data->to_dir,
3174 if (pipe_msg == PIPEMSG_DONE)
3176 PipeRead(*fd, &rc, sizeof(int));
3177 full_name = PipeReadString(*fd);
3181 fprintf(stderr, "Internal error in MakeFilePipeCB: bad pipe_msg %d\n",
3187 DPRINTF(("MakeFilePipeCB: n %d, pipe_msg %d, rc %d\n", n, pipe_msg, rc));
3189 /* arrange for the modified directory to be updated */
3190 DirectoryEndModify(cb_data->to_host, cb_data->to_dir);
3192 /* close the pipe and cancel the callback */
3196 /* Store away the newly created file so we later on we can
3200 MakeFileDoneData * data = (MakeFileDoneData *)cb_data->callback_data;
3201 DialogCallbackStruct * call_struct = data->call_struct;
3202 FileMgrData * file_mgr_data = call_struct->file_mgr_data;
3204 file_mgr_data->scrollToThisDirectory = cb_data->to_dir;
3205 file_mgr_data->scrollToThisFile = cb_data->to_file;
3208 /* call the callback routine */
3209 if (cb_data->finish_callback)
3210 (*cb_data->finish_callback)(cb_data->callback_data, full_name, rc);
3212 /* free callback data */
3214 XtFree(cb_data->to_host);
3216 /* Don't free to_dir and to_file. We used this to remember
3217 which file so later on we can scroll to it.
3218 XtFree(cb_data->to_dir);
3219 XtFree(cb_data->to_file);
3222 XtFree((char *)cb_data);
3226 /*--------------------------------------------------------------------
3228 * Start the background process and set up callback for the pipe.
3229 *------------------------------------------------------------------*/
3235 char *directory_name,
3238 void (*finish_callback)(),
3239 XtPointer callback_data)
3241 static char *pname = "MakeFile";
3242 MakeFileCBData *cb_data;
3243 char to_host[MAX_PATH];
3244 char to_dir[MAX_PATH];
3245 char to_file[MAX_PATH];
3250 /* get host & path of the target file */
3251 GetTarget(host_name, directory_name, new_name, to_host, to_dir, to_file);
3253 /* mark the target directory as being modified in the directory cache */
3254 DirectoryBeginModify(to_host, to_dir);
3256 /* parent: set up callback to get the pipe data */
3257 cb_data = XtNew(MakeFileCBData);
3258 cb_data->to_host = XtNewString(to_host);
3259 cb_data->to_dir = XtNewString(to_dir);
3260 cb_data->to_file = XtNewString(to_file);
3261 cb_data->finish_callback = finish_callback;
3262 cb_data->callback_data = callback_data;
3267 /* fork the process that does the actual work */
3271 DirectoryAbortModify(to_host, to_dir);
3273 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
3274 pname, getppid(), getpid(), errno, strerror(errno));
3281 DBGFORK(("%s: child forked, pipe %d\n", pname, pipe_fd[1]));
3283 close(pipe_fd[0]); /* child won't read from the pipe */
3285 rc = MakeFileProcess(pipe_fd[1], to_host, to_dir, to_file, type);
3288 DBGFORK(("%s: child exiting\n", pname));
3293 DBGFORK(("%s: forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
3295 /* parent: set up callback to get the pipe data */
3296 close(pipe_fd[1]); /* parent won't write the pipe */
3298 cb_data->child = pid;
3300 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
3301 pipe_fd[0], (XtPointer)XtInputReadMask,
3302 MakeFilePipeCB, (XtPointer)cb_data);
3306 /*=============================================================
3308 * The following routines handle the creation of files from
3309 * buffers: MakeFilesFromBuffers and MakeFilesFromBuffersDT
3312 *=============================================================*/
3315 MakeFilesFromBuffers(
3316 FileMgrData *file_mgr_data,
3321 BufferInfo *buffer_set,
3323 void (*finish_callback)(),
3324 XtPointer callback_data)
3326 return _FileMoveCopy ((XtPointer)file_mgr_data, NULL, directory, host,
3327 host_set, file_set, buffer_set, num_of_buffers,
3328 0, NULL, finish_callback, callback_data);
3333 MakeFilesFromBuffersDT(
3334 FileViewData *file_view_data,
3338 BufferInfo *buffer_set,
3340 DesktopRec *desktopWindow,
3341 void (*finish_callback)(),
3342 XtPointer callback_data)
3344 return _FileMoveCopy ((XtPointer)file_view_data, NULL, directory,
3346 host_set, file_set, buffer_set, num_of_buffers,
3347 0, desktopWindow, finish_callback, callback_data);
3351 /*====================================================================
3353 * CreateFileFromBuffer
3354 * Routine to create a file from a buffer
3356 *==================================================================*/
3360 CreateFileFromBuffer(int pipe_s2m,
3362 char *fully_qualified_name,
3369 Boolean BufferIsExecutable=FALSE;
3370 char *err_msg, *err_arg, *tmpStr;
3371 char *format_str, *strerror_str;
3372 int format_param_len=20;
3378 /* Set the permissions depending if buffer is a */
3379 /* file or an execuatable */
3380 if (_DtIsBufferExecutable(buffer,size))
3382 mode = S_IRUSR | S_IWUSR | S_IXUSR |
3383 S_IRGRP | S_IWGRP | S_IXGRP |
3384 S_IROTH | S_IWOTH | S_IXOTH;
3388 mode = S_IRUSR | S_IWUSR |
3393 /* Create the target file */
3394 if ((fnew = open(fully_qualified_name, O_CREAT| O_WRONLY, mode)) < 0)
3396 DPRINTF(("CreateBufferFromFile: Could not create %s\n",
3397 fully_qualified_name));
3403 /* Write the buffer to the target file */
3404 if ((rc = write(fnew, buffer, size)) < 0 )
3406 DPRINTF (("CreateBufferFromFile: Could not write buffer to %s\n",
3407 fully_qualified_name));
3413 DPRINTF (("CreateBuffeFromFile: Target file %s created\n",
3414 fully_qualified_name));
3424 tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
3425 err_msg = XtNewString(tmpStr);
3426 err_arg = XtNewString(fully_qualified_name);
3428 DPRINTF (("CreateBufferFromFile: EACCESS errno is %d\n",errno));
3431 err_msg = strerror(savedError);
3434 DPRINTF (("CreateBufferFromFile: %s\n", err_msg));
3437 /* Write error message on pipe so */
3438 /* that the parent process will */
3439 /* display a dialog */
3440 PipeWriteErrmsg(pipe_s2m, rc, err_msg, err_arg);
3441 if (err_msg) XtFree(err_msg);
3442 if (err_arg) XtFree(err_arg);
3453 * DisplayDuplicateOpError - Used in FileOpPipeCallback when a duplicate
3454 * operation like move/copy/link a file onto the same file is performed,
3455 * this routine gets called and displays an error message.
3459 DisplayDuplicateOpError(
3460 FileOpCBData *cb_data,
3464 char *msgptr,*err_msg,*title,*tchar;
3465 Widget dialogwidget;
3467 if (cb_data->mode == MOVE_FILE)
3469 if(cb_data->callback_data == NULL)
3470 if(initiating_view == NULL)
3474 title = XtCalloc(1,strlen(GETMESSAGE(9,73,"Move"))+
3475 strlen(GETMESSAGE(9,94,"Error"))+5);
3476 tchar = XtNewString(GETMESSAGE(9,73,"Move"));
3477 sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3479 err_msg = GETMESSAGE(11,135,"Cannot move object %s onto itself");
3482 else if (cb_data->mode == COPY_FILE)
3484 title = XtCalloc(1,strlen(GETMESSAGE(9,72,"Copy"))+
3485 strlen(GETMESSAGE(9,94,"Error"))+5);
3486 tchar = XtNewString(GETMESSAGE(9,72,"Copy"));
3487 sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3489 if(cb_data->callback_data == NULL)
3491 if(cb_data->file_mgr_data && cb_data->file_mgr_data->toolbox)
3497 err_msg = GETMESSAGE(11,136,"Cannot copy object %s onto itself");
3501 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");
3506 title = XtCalloc(1,strlen(GETMESSAGE(9,74,"Link"))+
3507 strlen(GETMESSAGE(9,94,"Error"))+5);
3508 tchar = XtNewString(GETMESSAGE(9,74,"Link"));
3509 sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3511 if(cb_data->callback_data == NULL)
3513 err_msg = GETMESSAGE(11,137,"Cannot link object %s onto itself");
3517 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");
3521 msgptr = XtCalloc(1,strlen(err_msg)+strlen(cb_data->updates[index].file)+10);
3522 sprintf(msgptr,err_msg,cb_data->updates[index].file);
3524 if(cb_data->callback_data)
3525 dialogwidget = ((RenameDoneData *)(cb_data->callback_data))->w;
3527 dialogwidget = toplevel;
3528 _DtMessage (dialogwidget,title, msgptr, NULL, HelpRequestCB);
3535 /*==============================================================
3537 * appendErrorMessage
3539 * if "arg" is not null, "new" is assumed to include %s
3540 * "message" is re-allocated and so will have a different
3541 * address than when the function was called
3543 * usage: errorMsg = appendErrorMessage(errorMsg,errStr,file);
3545 *==============================================================
3549 appendErrorMessage(String message, String new, String arg)
3554 newMessage = XtNewString(new);
3557 newMessage = XtMalloc(strlen(new) + strlen(arg) + 1);
3558 sprintf(newMessage,new,arg);
3561 if (message == NULL)
3563 message = XtRealloc(message, (strlen(newMessage) + 2));
3567 message = XtRealloc(message, (strlen(message) + strlen(newMessage) + 2));
3569 strcat(message,newMessage);
3570 strcat(message,"\n");
3576 } /* end appendErrorMessage */
3579 DisplayErrorMessage(
3587 localstr = (char *) XtMalloc(strlen(errMsg)+strlen(from)+strlen(tdir) + 10 );
3588 sprintf(localstr,errMsg,tdir,from);
3589 PipeWriteErrmsg(pipe_s2m, -1, localstr, NULL);
3597 char filename [MAX_PATH];
3599 int slen = strlen(source_path);
3601 if(slen > strlen(dest_path))
3603 strcpy (filename, dest_path);
3604 cptr = strchr(&filename[slen-1],'/');
3607 return ((strcmp(source_path,filename) == 0)?True:False);