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 ************************************<+>*************************************/
77 #include <sys/types.h>
79 #include <sys/signal.h>
88 #include <sys/select.h>
91 #if defined(_AIX)|| defined(hpux)
101 #include <Xm/MwmUtil.h>
102 #include <Xm/TextF.h>
103 #include <Xm/ScrollBar.h>
104 #include <X11/ShellP.h>
105 #include <X11/Shell.h>
106 #include <X11/Xutil.h>
107 #include <X11/Xatom.h>
110 #include <X11/extensions/shape.h>
114 #include <Dt/IconP.h>
115 #include <Dt/IconFile.h>
116 #include <Dt/Action.h>
117 #include <Dt/Connect.h>
119 #include <Dt/DtNlUtils.h>
120 #include <Dt/HourGlass.h>
121 #include <Dt/SharedProcs.h>
126 #include "SharedProcs.h"
134 #include "SharedMsgs.h"
135 #include "sharedFuncs.h"
138 /* Static Function declarations */
140 static Boolean CreateFileFromBuffer(
143 char *fully_qualified_name,
146 static String appendErrorMessage(
150 static void DisplayErrorMessage(
155 static Boolean IsInParentDir(char *from,char *to);
157 /* the amount of time we wait for a file move/copy to complete */
158 /* @@@ should make this a resource */
159 #define FILE_MOVE_COPY_WAIT_TIME 2
162 /* types of messages sent through the pipe */
163 #define PIPEMSG_FILEOP_ERROR 1
164 #define PIPEMSG_EXIST_ERROR 2
165 #define PIPEMSG_OTHER_ERROR 3
166 #define PIPEMSG_CONFIRM 4
167 #define PIPEMSG_TARGET_TIME 5
168 #define PIPEMSG_FILE_MODIFIED 6
169 #define PIPEMSG_DONE 7
170 #define PIPEMSG_REPLACE_RENAME 8
171 #define PIPEMSG_REPLACE_RENAME_SAME 9
172 #define PIPEMSG_REPLACE_MERGE 10
173 #define PIPEMSG_MULTICOLLIDE 11
174 #define PIPEMSG_MULTICOLLIDE_SAME 12
175 #define PIPEMSG_MOVE_TO_SAME_DIR 13
177 /* the following messages are also defined & used in OverWrite.c */
178 #define PIPEMSG_CANCEL 101
179 #define PIPEMSG_PROCEED 102
180 #define PIPEMSG_MERGE 103
181 #define PIPEMSG_REPLACE_BUFFER 104
182 #define PIPEMSG_RENAME_BUFFER 105
183 #define PIPEMSG_MULTI_PROCEED 106
185 extern int G_dropx,G_dropy;
187 /* callback data for file move/copy/link */
192 BufferInfo bufferInfo;
195 Boolean operationStatus;
202 FileMgrData *file_mgr_data;
203 FileMgrRec *file_mgr_rec;
204 FileViewData *file_view_data;
205 DesktopRec *desktopWindow;
206 int pipe_m2s; /* pipe main to slave */
207 int pipe_s2m; /* pipe slave to main */
213 void (*finish_callback)();
214 XtPointer callback_data;
219 /* callback data for file rename */
224 FileViewData *file_view_data;
225 DesktopRec *desktopWindow;
227 char *directory_name;
234 /* callback data for create file/directory */
240 void (*finish_callback)();
241 XtPointer callback_data;
247 DisplayDuplicateOpError(FileOpCBData *cb_data,int index);
251 /*====================================================================
253 * Routine for sending data through a pipe
255 *==================================================================*/
257 /*--------------------------------------------------------------------
259 * Read data from the pipe
260 *------------------------------------------------------------------*/
268 static int whined_fd = -1;
274 rc = read(fd, (char *)buf + n, len - n);
277 else if (rc < 0 && errno == EINTR)
287 "PipeRead: broken pipe, ppid=%d pid=%d fd=%d\n",
288 getppid(), getpid(), fd);
293 perror("dtfile: read failed in PipeRead");
304 /*--------------------------------------------------------------------
306 * write a string to the pipe
307 *------------------------------------------------------------------*/
317 oldPipe = (void (*)())signal(SIGPIPE, SIG_IGN);
324 if (write(fd, &len, sizeof(short)) < 0) {
329 sent = write(fd, s, len);
331 signal(SIGPIPE, oldPipe);
337 /*--------------------------------------------------------------------
339 * read a string from the pipe
340 *------------------------------------------------------------------*/
351 if (PipeRead(fd, &len, sizeof(short)) != sizeof(short))
358 s = (char *)XtMalloc(len + 1);
359 if (PipeRead(fd, s, len) != len)
370 /*--------------------------------------------------------------------
372 * write an error message to the pipe
373 *------------------------------------------------------------------*/
382 short pipe_msg = PIPEMSG_FILEOP_ERROR;
384 DPRINTF(("PipeWriteErrmsg: sending error %d \"%s\"\n", rc, msg));
386 write(fd, &pipe_msg, sizeof(short));
387 write(fd, &rc, sizeof(int));
388 PipeWriteString(fd, msg);
389 PipeWriteString(fd, arg);
395 /*====================================================================
398 * Run a background process to move/copy/link files dropped
399 * on a dtfile window or icon.
401 *==================================================================*/
403 /*--------------------------------------------------------------------
404 * moveCopyLinkCancel:
405 * Cancel-button callback for overwrite confirmation dialog
406 *------------------------------------------------------------------*/
408 int filop_confirm_fd = -1; /* @@@ can't we pass this in client_data? */
413 XtPointer client_data,
414 XtPointer call_data )
416 const int rc = PIPEMSG_CANCEL;
418 /* close the dialog */
419 XtUnmanageChild((Widget)client_data);
420 XmUpdateDisplay((Widget)client_data);
421 XtDestroyWidget((Widget)client_data);
423 /* send return code through the pipe to the background proc */
424 write(filop_confirm_fd, &rc, sizeof(int));
425 filop_confirm_fd = -1;
429 /*--------------------------------------------------------------------
431 * Ok-button callback for overwrite confirmation dialog
432 *------------------------------------------------------------------*/
437 XtPointer client_data,
438 XtPointer call_data )
440 const int rc = PIPEMSG_PROCEED;
442 /* close the dialog */
443 XtUnmanageChild((Widget)client_data);
444 XmUpdateDisplay((Widget)client_data);
445 XtDestroyWidget((Widget)client_data);
447 /* send affirmative return code through the pipe to the background proc */
448 write(filop_confirm_fd, &rc, sizeof(int));
449 filop_confirm_fd = -1;
453 /*--------------------------------------------------------------------
455 * Error handler for FileManip when called in the background process
456 *------------------------------------------------------------------*/
464 int pipe_fd = (int) (intptr_t) w; /* @@@ Hack! @@@
465 In the background process we call FileManip with
466 the file descriptor for the pipe instead of a
467 widget id. We rely on the fact that FileManip
468 never uses the widget as a widget, but only
469 passes it to the error handler. */
471 /* write the error message to the pipe */
472 PipeWriteErrmsg(pipe_fd, -1, message1, message2);
476 /*--------------------------------------------------------------------
478 * Send a message through the pipe that informs the main process
479 * that we are about to modify a directory or that a file has been
481 *------------------------------------------------------------------*/
496 struct stat stat_buf;
499 /* if first operation on target dir, send timestamp */
502 if (stat(to, &stat_buf) == 0)
504 modify_time = stat_buf.st_mtime;
505 pipe_msg = PIPEMSG_TARGET_TIME;
506 write(pipe_fd, &pipe_msg, sizeof(short));
507 write(pipe_fd, &modify_time, sizeof(long));
511 /* if first operation on source dir, get timestamp of source dir */
513 j = updates[i].first_index;
514 if (mode == MOVE_FILE && !updates[j].time_sent)
518 dir_path = ResolveLocalPathName(updates[i].host,
519 updates[i].directory,
524 if (stat(dir_path, &stat_buf) == 0)
525 modify_time = stat_buf.st_mtime;
527 updates[j].time_sent = True;
530 /* send the modify message */
531 pipe_msg = PIPEMSG_FILE_MODIFIED;
532 write(pipe_fd, &pipe_msg, sizeof(short));
533 write(pipe_fd, &i, sizeof(int));
534 write(pipe_fd, &modify_time, sizeof(long));
535 PipeWriteString(pipe_fd, target_file);
538 /*--------------------------------------------------------------------
539 * FileMoveCopyProcess:
540 * Main routine of the background process
542 * This routine has two basic modes of operation:
543 * It is given a list of source files and a target directory,
544 * and performs an operation on the source files. This mode
545 * is used for drag & drop operations where a user can
546 * select multiple source files and then drop them on a
547 * target directory to either move, copy, or copy-as-link
548 * the source files to the target directory. The source
549 * and target directories must be different.
550 * It is given a single source file and a target file. The
551 * target can be either a directory or a file. This mode
552 * is used for menu-intiated move, copy, or copy-as-link
553 * operations. The source and target directories can be
555 * The source file(s) are given in updates; the destination is
556 * in host, dirctory, to_file. If to_file is NULL, the
557 * first mode (drag & drop) is assumed, otherwise assume
558 * menu-initiated mode.
560 *------------------------------------------------------------------*/
572 DesktopRec *desktopWindow)
574 char * target_dir, * from, * to;
575 int i, j, rc, result;
576 Boolean return_val = False;
579 char *tmpStr, *target_file;
580 struct stat stat_buf, from_stat_buf;
584 int *sameIndex = NULL, *sameConfirmType = NULL;
585 Boolean first_op = True;
589 String permissionErrors = NULL;
590 Boolean targetChecked = FALSE;
591 Boolean targetError = FALSE;
592 Boolean CopyError=FALSE,MoveError1=FALSE,MoveError2=FALSE;
593 char *CopyString=NULL,*MoveString1=NULL,*MoveString2=NULL;
596 /* Get the fully qualified destination path. */
597 target_dir = (char *)ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
598 if( TT_OK != tt_status )
600 char msg1[2*MAX_PATH];
602 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
603 directory, host, host);
605 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
606 directory, host, host);
608 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
609 pipe_msg = PIPEMSG_FILEOP_ERROR;
611 write(pipe_s2m, &pipe_msg, sizeof(short));
612 write(pipe_s2m, &rc, sizeof(int));
616 DtEliminateDots(target_dir);
618 for (i = 0; i < file_count; i++)
622 /* get full name of the source file, if just */
623 /* dealing with regular files */
624 if (mode != MAKE_BUFFER)
626 from = ResolveLocalPathName(updates[i].host,
627 updates[i].directory,
633 char msg1[2*MAX_PATH];
636 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
637 updates[i].directory, updates[i].host, updates[i].host);
639 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
640 updates[i].directory, updates[i].host, updates[i].host);
642 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
646 /* do some extra error checking if a target filename is specified */
647 /* this is meant for the case of a menu-initiated operation */
650 /* Verify that the target directory already exists */
651 if ( (stat(target_dir, &stat_buf) != 0) ||
652 (! S_ISDIR(stat_buf.st_mode) ) )
657 GETMESSAGE(11,41,"The folder\n%s\ndoes not exist."));
658 PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
666 /* check for a drop of a directory onto itself */
667 if (updates[i].app_man_dir)
669 char *temp_dir = XtNewString(target_dir);
671 temp_dir = _DtResolveAppManPath(temp_dir, updates[i].app_man_dir);
672 if (mode == MOVE_FILE && strcmp(temp_dir, from) == 0)
677 GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
678 PipeWriteErrmsg( pipe_s2m, -1, msg, temp_dir );
687 else if (mode == MOVE_FILE && strcmp(target_dir, from) == 0)
692 GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
693 PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
699 else if (mode == MOVE_FILE && stat(from, &stat_buf) == 0 &&
700 S_ISDIR(stat_buf.st_mode) && DirectoryBusy(from))
704 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."));
706 PipeWriteErrmsg( pipe_s2m, -1, msg, from );
714 /* for copy operations, check for read permission on the source file */
715 /* the error message is appended to a list and dealt with later */
716 /* the current file is not processed */
717 if (mode == COPY_FILE)
718 if (CheckAccess(from,R_OK) == -1)
723 /* 'errno' is not giving correct results like 'ENOENT' in order to
724 use it here, may be because of the other system calls in
727 if (stat(from, &sbuf) < 0)
728 tmpStr = (GETMESSAGE(28,13,"Object:\n\n %s\n\n does not exist in the file system"));
730 tmpStr = GetSharedMessage(CANT_READ_ERROR);
732 permissionErrors = appendErrorMessage(permissionErrors, tmpStr, from);
739 if (strcmp(target_dir, "/") == 0)
741 target_file = (char *)XtMalloc(strlen(target_dir) +
742 strlen(updates[i].file) + 1);
743 sprintf(target_file, "%s%s", target_dir, updates[i].file);
747 target_file = (char *)XtMalloc(strlen(target_dir) +
748 strlen(updates[i].file) + 2);
749 sprintf(target_file, "%s/%s", target_dir, updates[i].file);
754 if (strcmp(target_dir, "/") == 0)
756 target_file = (char *)XtMalloc(strlen(target_dir) +
757 strlen(to_file) + 1);
758 sprintf(target_file, "%s%s", target_dir, to_file);
762 target_file = (char *)XtMalloc(strlen(target_dir) +
763 strlen(to_file) + 2);
764 sprintf(target_file, "%s/%s", target_dir, to_file);
767 if (updates[i].app_man_dir)
768 target_file = _DtResolveAppManPath(target_file,
769 updates[i].app_man_dir);
770 /* check if source and target files are the same.
771 * if they are the same, set a flag noting that they are. If the
772 * the operation is a move, it doesn't make any sense to move it, so
773 * send back a MOVE_TO_SAME_DIR msg.
776 if ((mode != MAKE_BUFFER) && (strcmp(target_file, from) == 0))
778 if (mode == MOVE_FILE && stat(target_file, &stat_buf) == 0)
780 if(S_ISDIR(stat_buf.st_mode))
782 pipe_msg = PIPEMSG_MOVE_TO_SAME_DIR;
783 write(pipe_s2m, &pipe_msg, sizeof(short));
784 write(pipe_s2m, &i, sizeof(int));
793 /* for copy operations, check for write permission on the target */
795 /* for move operations, check for write permission on the source and */
796 /* target directories */
797 /* the error message is appended to a list and dealt with later */
798 /* the current file is not processed */
799 if (mode == COPY_FILE)
801 if (CheckAccess(target_dir,W_OK) == -1)
805 if(CopyString == NULL)
806 CopyString = XtNewString(from);
809 CopyString = (char *) XtRealloc(CopyString,strlen(CopyString)+
811 strcat(CopyString,"\n");
812 strcat(CopyString,from);
817 else if (mode == MOVE_FILE)
819 Boolean error = FALSE;
820 if (targetChecked || CheckAccess(target_dir,W_OK) == -1)
823 if(MoveString1 == NULL)
824 MoveString1 = XtNewString(from);
827 MoveString1=(char *)XtRealloc(MoveString1,strlen(MoveString1)+
829 strcat(MoveString1,"\n");
830 strcat(MoveString1,from);
832 error = targetError = TRUE;
833 targetChecked = TRUE;
835 if (CheckAccess(_DtPName(from),W_OK) == -1)
838 if(MoveString2 == NULL)
839 MoveString2 = XtNewString(from);
842 MoveString2 = (char *)XtRealloc(MoveString2,strlen(MoveString2)+
844 strcat(MoveString2,"\n");
845 strcat(MoveString2,from);
849 if (error || targetError)
856 /* check if target file already exists */
857 if (stat(target_file, &stat_buf) == 0)
859 /* target file already exists: remember and deal with it later */
860 if(mode == MOVE_FILE && S_ISDIR(stat_buf.st_mode)
861 && DirectoryBusy(target_file))
865 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."));
867 PipeWriteErrmsg( pipe_s2m, -1, msg, target_file );
873 if (sameIndex == NULL)
875 sameIndex = (int *)XtMalloc(file_count*sizeof(int));
876 sameConfirmType = (int *)XtMalloc(file_count*sizeof(int));
878 sameIndex[sameCount] = i;
880 /* determine how to set the pipe message */
881 if (mode == MAKE_BUFFER)
883 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
887 stat(from, &from_stat_buf);
888 if ( S_ISDIR(from_stat_buf.st_mode) &&
889 S_ISDIR(stat_buf.st_mode) &&
892 /* if its a directory and there already is a directory of the
893 * same name the user may want to merge the directories into
894 * one directory. But if the directory to be copied is being
895 * copied into the same directory it came from, it doesn't make
896 * sense to merge. Set up message to REPLACE_RENAME_SAME
897 * indicating it is being copied from and to the same directory
900 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
902 sameConfirmType[sameCount] = PIPEMSG_REPLACE_MERGE;
906 /* If the copy/move/link is to the same directory, set up a
907 * different case then when the op is happening from different
911 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
913 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
915 } /* endif mode != MAKE_BUFFER */
919 if (mode != MAKE_BUFFER)
920 XtFree ((char *) from);
922 XtFree ((char *) target_file);
924 } /* endif targetfile already exists */
926 if ((isContainer = (to_file == NULL)))
932 * Note: it is important that SendModifyMsg is called before any
933 * changes are made to either the source or target directory.
934 * This is because SendModifyMsg is supposed to obtain and send
935 * the time stamp of the directories BEFORE any operation. If
936 * the wrong timestamp is sent, the window will be updated and
937 * redrawn twice instead of just once.
939 SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, i,
943 if (mode == MAKE_BUFFER)
945 /* Call CreateFileFromBuffer */
946 return_val = CreateFileFromBuffer(pipe_s2m, to,
948 updates[i].bufferInfo.buf_ptr,
949 updates[i].bufferInfo.size);
953 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
954 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
956 FileOpError, True, DESKTOP);
958 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
960 FileOpError, True, NOT_DESKTOP);
961 XtFree( (char *) from );
964 XtFree ((char *) target_file);
968 if(CopyError == TRUE)
971 errMsg = GETMESSAGE(11,48,
972 "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");
973 DisplayErrorMessage(pipe_s2m,errMsg,CopyString,target_dir);
975 permissionErrors = NULL;
979 if(MoveError1 == TRUE)
982 errMsg = GETMESSAGE(11,49,
983 "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");
984 DisplayErrorMessage(pipe_s2m,errMsg,MoveString1,target_dir);
986 permissionErrors = NULL;
990 if(MoveError2 == TRUE)
993 errMsg = GETMESSAGE(11,50,
994 "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");
995 DisplayErrorMessage(pipe_s2m,errMsg,MoveString2,target_dir);
997 permissionErrors = NULL;
1003 /* If there were any permissions errors, show the error message */
1004 if (permissionErrors != NULL)
1006 PipeWriteErrmsg(pipe_s2m, -1, permissionErrors, NULL);
1007 XtFree(permissionErrors);
1012 * Now deal with with the cases where we found that the target file
1019 * @@@ Note: The code below for sending a target-time pipe message
1020 * at this point shouldn't really be necessary.
1021 * The problem is that the target directory time stamp MUST be
1022 * obtained BEFORE any changes are made to the directory;
1023 * otherwise, the window will be updated and redrawn twice instead
1024 * of just once. Unfortunately, currently, if the user chooses to
1025 * replace or rename the existing file, the rename or delete
1026 * operation is done in the main process (inside the
1027 * replace_rename_ok_callback in Overwrite.c), instead of here in
1028 * the child process where it belongs (the main process shouldn't
1029 * do any file system operations because they could block for a
1030 * long time on a slow server). If and when overwrite dialog code
1031 * is fixed, the code below can be deleted; the target-time
1032 * message will then be sent by the call to SendModifyMsg further
1033 * below after the call to PipeRead.
1037 if (stat(target_dir, &stat_buf) == 0)
1039 modify_time = stat_buf.st_mtime;
1040 pipe_msg = PIPEMSG_TARGET_TIME;
1041 write(pipe_s2m, &pipe_msg, sizeof(short));
1042 write(pipe_s2m, &modify_time, sizeof(long));
1047 /* send message to main process to display dialog (and possibly remove/rename files) */
1048 if (file_count == 1)
1050 if (to_file == NULL) /* note target_file here is only file name, above it is full path */
1051 target_file = updates[sameIndex[0]].file;
1053 target_file = to_file;
1054 pipe_msg = sameConfirmType[0];
1055 DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
1056 write(pipe_s2m, &pipe_msg, sizeof(short));
1057 DPRINTF(("FileMoveCopyProcess: sending: mode %d directory \"%s\" file \"%s\" \n",
1058 mode, directory, target_file));
1059 write(pipe_s2m, &mode, sizeof(int));
1060 PipeWriteString(pipe_s2m, directory);
1061 PipeWriteString(pipe_s2m, target_file);
1065 int processCount=file_count-errorCount;
1067 /* If the copy/move/link is to the same directory, set up a
1068 * different case then when the op is happening from different
1072 pipe_msg = PIPEMSG_MULTICOLLIDE_SAME;
1074 pipe_msg = PIPEMSG_MULTICOLLIDE;
1076 DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
1077 write(pipe_s2m, &pipe_msg, sizeof(short));
1078 DPRINTF(("FileMoveCopyProcess: sending: mode %d processCount %d sameCount %d directory \"%s\"\n",
1079 mode, processCount, sameCount, directory));
1080 write(pipe_s2m, &mode, sizeof(int));
1081 write(pipe_s2m, &processCount, sizeof(int));
1082 write(pipe_s2m, &sameCount, sizeof(int));
1083 PipeWriteString(pipe_s2m, directory);
1084 DPRINTF(("FileMoveCopyProcess: sending %d filename strings\n", sameCount));
1085 for (i = 0; i < sameCount; i++)
1086 PipeWriteString(pipe_s2m, updates[sameIndex[i]].file);
1089 /* wait for reply from main process */
1091 PipeRead(pipe_m2s, &rc, sizeof(int));
1092 DPRINTF(("FileMoveCopyProcess: woke up after confirm, rc %d\n", rc));
1093 if (rc != PIPEMSG_CANCEL)
1095 /* affirmative reply: do the operation */
1096 for(i = 0; i < sameCount; i++)
1099 if (rc != PIPEMSG_RENAME_BUFFER)
1101 SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, j,
1105 if (rc == PIPEMSG_MULTI_PROCEED)
1108 PipeRead(pipe_m2s, &opvalue, sizeof(int));
1113 if (mode != MAKE_BUFFER)
1115 from = ResolveLocalPathName( updates[j].host,
1116 updates[j].directory,
1120 if( TT_OK != tt_status )
1122 char msg1[2*MAX_PATH];
1125 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1126 updates[j].directory, updates[j].host,
1129 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1130 updates[j].directory, updates[j].host,
1133 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
1140 if ( (isContainer = (to_file == NULL)) )
1146 to = (char *)XtMalloc(strlen(target_dir) + strlen(to_file) + 2);
1147 sprintf(to, "%s/%s", target_dir, to_file);
1152 /* check the return code for type of message and */
1153 /* perform the appropriate action */
1158 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
1159 return_val = FileManip((Widget) (intptr_t) pipe_s2m, MERGE_DIR, from,
1161 FileOpError, True, DESKTOP);
1163 return_val = FileManip((Widget) (intptr_t) pipe_s2m, MERGE_DIR, from,
1165 FileOpError, True, NOT_DESKTOP);
1168 case PIPEMSG_REPLACE_BUFFER:
1169 target_file = (char *)XtMalloc(strlen(to) + strlen(updates[j].file)
1171 sprintf(target_file, "%s/%s", to, updates[j].file);
1172 DPRINTF (("file is %s",updates[j].file));
1173 return_val = CreateFileFromBuffer(pipe_s2m,
1176 updates[j].bufferInfo.buf_ptr,
1177 updates[j].bufferInfo.size);
1178 XtFree((char *)target_file);
1181 case PIPEMSG_RENAME_BUFFER:
1183 renamed_file = PipeReadString(pipe_m2s);
1185 SendModifyMsg(pipe_s2m, mode, first_op, to, updates, j, renamed_file);
1186 target_file = (char *)XtMalloc(strlen(to) + strlen(renamed_file)
1188 sprintf(target_file, "%s/%s", to, renamed_file);
1189 DPRINTF(("file is %s",renamed_file));
1190 return_val = CreateFileFromBuffer(pipe_s2m,
1193 updates[j].bufferInfo.buf_ptr,
1194 updates[j].bufferInfo.size);
1195 XtFree((char *) target_file);
1200 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
1201 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
1202 isContainer,FileOpError, True,
1206 /* if the operation (move/copy/link) is happening from
1207 * and to the same folder, we want to create a new name
1208 * for the object for which the operation is happening
1213 char path[MAX_PATH], newDir[MAX_PATH],
1218 generate_NewPath(path,path);
1219 split_path(path, newDir, newFile);
1220 toFile = (char *)XtMalloc(strlen(newDir) +
1221 strlen(newFile) + 3);
1222 strcpy(toFile, newDir);
1223 strcat(toFile, "/");
1224 strcat(toFile, newFile);
1226 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from,
1227 toFile, False, FileOpError,
1233 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from,
1234 to, isContainer, FileOpError,
1239 if (to_file != NULL)
1241 XtFree ((char *) to);
1245 }/*end if rc != PIPEMSG_CANCEL*/
1248 XtFree((char *)sameIndex);
1250 XtFree((char *)sameConfirmType);
1251 sameConfirmType = NULL;
1253 } /* endif sameCount != 0 */
1256 pipe_msg = PIPEMSG_DONE;
1257 if (rc != PIPEMSG_CANCEL)
1258 rc = return_val? 0: -1;
1261 write(pipe_s2m, &pipe_msg, sizeof(short));
1262 write(pipe_s2m, &rc, sizeof(int));
1264 XtFree ((char *) target_dir);
1271 /*--------------------------------------------------------------------
1272 * FileMoveCopyProcessDesktop:
1273 * Main routine of the background process that handles files
1274 * dropped in desktop icons.
1275 *------------------------------------------------------------------*/
1278 FileMoveCopyProcessDesktop(
1286 DesktopRec *desktopWindow)
1290 Boolean first_op = True;
1291 Boolean return_val = False;
1293 Tt_status tt_status;
1295 /* Get the fully qualified destination path. */
1296 to = ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
1297 if( TT_OK != tt_status )
1299 char msg1[2*MAX_PATH];
1301 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1302 directory, host, host);
1304 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1305 directory, host, host);
1307 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
1308 pipe_msg = PIPEMSG_FILEOP_ERROR;
1310 write(pipe_s2m, &pipe_msg, sizeof(short));
1311 write(pipe_s2m, &rc, sizeof(int));
1314 DtEliminateDots(to);
1316 for (i = 0; i < file_count; i++)
1318 /* get full name of the source file, if just */
1319 /* dealing with regular files */
1320 if (mode != MAKE_BUFFER)
1322 from = ResolveLocalPathName(updates[i].host,
1323 updates[i].directory,
1329 char msg[2*MAX_PATH];
1332 sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1333 updates[i].directory, updates[i].host, updates[i].host);
1335 sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1336 updates[i].directory, updates[i].host, updates[i].host);
1338 PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
1340 else if (strcmp(to, from) == 0)
1342 char msg[2*MAX_PATH];
1344 sprintf(msg,GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"),to);
1345 PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
1346 XtFree ((char *) from);
1349 } /* end if dealing with regular files */
1352 SendModifyMsg(pipe_s2m, mode, first_op, to, updates, i, updates[i].file);
1356 if (mode == MAKE_BUFFER)
1360 if (strcmp(to, "/") == 0)
1362 target_file = (char *) XtMalloc(strlen(to) +
1363 strlen(updates[i].file) + 1);
1364 sprintf(target_file, "%s%s", to, updates[i].file);
1368 target_file = (char *) XtMalloc(strlen(to) +
1369 strlen(updates[i].file) + 2);
1370 sprintf(target_file, "%s/%s", to, updates[i].file);
1373 return_val = CreateFileFromBuffer(pipe_s2m,
1376 updates[i].bufferInfo.buf_ptr,
1377 updates[i].bufferInfo.size);
1381 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to, TRUE,
1382 FileOpError, True, DESKTOP);
1388 pipe_msg = PIPEMSG_DONE;
1389 rc = return_val? 0: -1;
1390 write(pipe_s2m, &pipe_msg, sizeof(short));
1391 write(pipe_s2m, &rc, sizeof(int));
1393 XtFree ((char *) to);
1399 RemoveIconFromWorkspace( char * iconName,
1402 DesktopRec *desktopWin;
1404 char fileName[MAX_PATH];
1407 for(i = 0; i < desktop_data->numIconsUsed; i++)
1409 desktopWin = desktop_data->desktopWindows[i];
1411 if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
1412 sprintf( fileName, "/%s", desktopWin->file_name );
1414 sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
1416 if( strcmp( fileName, iconName ) == 0 )
1420 Screen *currentScreen;
1422 char *workspace_name;
1424 screen = XDefaultScreen(XtDisplay(desktopWin->shell));
1426 XScreenOfDisplay(XtDisplay(desktopWin->shell), screen);
1427 rootWindow = RootWindowOfScreen(currentScreen);
1429 if(DtWsmGetCurrentWorkspace(XtDisplay(desktopWin->shell),
1430 rootWindow, &pCurrent) == Success)
1432 XGetAtomName (XtDisplay(desktopWin->shell), pCurrent);
1434 workspace_name = XtNewString("One");
1436 if( strcmp( workspace_name, desktopWin->workspace_name ) == 0 )
1438 RemoveDT( desktopWin->shell, (XtPointer) desktopWin,
1443 XtFree( desktopWin->dir_linked_to );
1444 desktopWin->dir_linked_to = XtNewString( targetDir );
1447 XtFree(workspace_name);
1453 ChangeWorkspaceIconLink( FileMgrData *fmd,
1458 DesktopRec *desktopWin;
1461 char fileName[MAX_PATH];
1464 for(i = 0; i < desktop_data->numIconsUsed; i++)
1466 desktopWin = desktop_data->desktopWindows[i];
1468 if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
1469 sprintf( fileName, "/%s", desktopWin->file_name );
1471 sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
1473 DtEliminateDots(fileName);
1474 if( strcmp( fileName, iconName ) == 0 )
1475 dirp = XtNewString(targetDir);
1476 else if(IsInParentDir(iconName,desktopWin->dir_linked_to))
1478 int index = strlen(iconPdir);
1479 char *tptr = desktopWin->dir_linked_to;
1481 dirp = XtCalloc( 1, strlen(targetDir)+ strlen(&tptr[index])+1);
1482 sprintf(dirp,"%s%s",targetDir,&tptr[index]);
1487 FileViewData *file_view_data;
1488 DirectorySet *directory_set;
1489 FileMgrData *file_mgr_data;
1490 Tt_status tt_status;
1491 char * full_dir_name;
1493 file_view_data = desktopWin->file_view_data;
1494 directory_set = (DirectorySet *)file_view_data->directory_set;
1495 file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
1498 fmd = file_mgr_data;
1499 FreeFileData( file_view_data->file_data, True );
1500 file_view_data->file_data = NULL;
1502 XtFree( desktopWin->dir_linked_to );
1503 desktopWin->dir_linked_to = XtNewString( dirp );
1504 DtEliminateDots(desktopWin->dir_linked_to);
1508 if (fmd->restricted_directory == NULL)
1509 desktopWin->restricted_directory = NULL;
1511 desktopWin->restricted_directory =
1512 XtNewString(fmd->restricted_directory);
1514 if (fmd->helpVol == NULL)
1515 desktopWin->helpVol = NULL;
1517 desktopWin->helpVol = XtNewString(fmd->helpVol);
1519 desktopWin->helpVol = XtNewString( fmd->helpVol );
1520 desktopWin->view = fmd->view;
1521 desktopWin->order = fmd->order;
1522 desktopWin->direction = fmd->direction;
1523 desktopWin->positionEnabled = fmd->positionEnabled;
1524 desktopWin->toolbox = fmd->toolbox;
1527 full_dir_name = ResolveLocalPathName(desktopWin->host,
1532 if( TT_OK == tt_status )
1534 FileData2 file_data2;
1538 DtEliminateDots (full_dir_name);
1541 IsToolBox = fmd->toolbox;
1545 if (strcmp(desktopWin->file_name, ".") == 0)
1546 ReadFileData2(&file_data2, full_dir_name, NULL, IsToolBox);
1548 ReadFileData2(&file_data2, full_dir_name, desktopWin->file_name,
1551 file_view_data->file_data = FileData2toFileData(&file_data2, &n);
1552 XtFree(full_dir_name);
1553 full_dir_name = NULL;
1556 ((DirectorySet *)file_view_data->directory_set)->name =
1559 SaveDesktopInfo(NORMAL_RESTORE);
1566 /*--------------------------------------------------------------------
1568 * Read and process data sent through the pipe.
1569 *------------------------------------------------------------------*/
1573 XtPointer client_data,
1577 FileOpCBData *cb_data = (FileOpCBData *)client_data;
1580 char *title, *err_msg, *err_arg;
1581 char *directory, *file, *target_file;
1585 int nSelected, nCollisions;
1587 static int status = 0;
1589 static ActionAreaItem replace_rename_actionItems[] = {
1590 {"Ok", 9, 27, NULL, NULL}, /* changed later based on mode */
1591 {"Cancel", 9, 28, replace_rename_cancel_callback, NULL},
1592 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_REN},
1595 ActionAreaDefn replace_renameActions = {
1596 XtNumber(replace_rename_actionItems),
1597 1, /* Cancel is default action */
1598 replace_rename_actionItems
1601 static ActionAreaItem replace_merge_actionItems[] = {
1602 {"Ok", 9, 27, replace_merge_ok_callback, NULL},
1603 {"Cancel", 9, 28, replace_merge_cancel_callback, NULL}, /* changed below depending on mode */
1604 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_MRG},
1607 ActionAreaDefn replace_mergeActions = {
1608 XtNumber(replace_merge_actionItems),
1609 1, /* Cancel is default action */
1610 replace_merge_actionItems
1613 static ActionAreaItem multicollide_actionItems[] = {
1614 {"Ok", 9, 27, NULL, NULL}, /* changed later based on Mode */
1615 {"Cancel", 9, 28, multicollide_cancel_callback, NULL}, /* changed below depending on mode */
1616 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_MULTI},
1619 ActionAreaDefn multicollideActions = {
1620 XtNumber(multicollide_actionItems),
1621 1, /* Cancel is default action */
1622 multicollide_actionItems
1626 /* Initialize Action Area structures based on mode */
1627 /* Set the appropriate callback routines */
1628 mode = cb_data->mode;
1632 replace_rename_actionItems[0].callback =
1633 buffer_replace_rename_ok_callback;
1634 multicollide_actionItems[0].callback =
1635 buffer_multicollide_ok_callback;
1638 replace_rename_actionItems[0].callback =
1639 replace_rename_ok_callback;
1640 multicollide_actionItems[0].callback =
1641 multicollide_ok_callback;
1646 /* read the next msg from the pipe */
1648 n = PipeRead(*fd, &pipe_msg, sizeof(short));
1649 DPRINTF(("FileOpPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
1654 case PIPEMSG_FILEOP_ERROR:
1655 PipeRead(*fd, &rc, sizeof(int));
1656 err_msg = PipeReadString(*fd);
1657 err_arg = PipeReadString(*fd);
1658 if (cb_data->desktop)
1659 FileOperationError(cb_data->file_view_data->widget,
1663 /* routine can be called with a NULL file_mgr_rec, use the
1664 * top level widget if this is the case.
1666 if(cb_data->file_mgr_rec)
1667 FileOperationError(cb_data->file_mgr_rec->file_window,
1670 FileOperationError(toplevel, err_msg, err_arg);
1674 if(cb_data->callback_data)
1676 RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
1677 ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
1678 ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
1680 status = PIPEMSG_FILEOP_ERROR;
1683 case PIPEMSG_CONFIRM:
1684 err_msg = PipeReadString(*fd);
1685 title = XtNewString(GETMESSAGE(9,11, "File Manager - Move/Copy/Link Warning"));
1686 filop_confirm_fd = cb_data->pipe_m2s;
1687 _DtMessageDialog(toplevel, title, err_msg, NULL, TRUE,
1688 moveCopyLinkCancel, moveCopyLinkOK, NULL,
1689 HelpRequestCB, False, QUESTION_DIALOG);
1694 case PIPEMSG_REPLACE_RENAME_SAME:
1695 /* filename collision: display replace/rename dialog */
1696 PipeRead(*fd, &mode, sizeof(int));
1697 directory = PipeReadString(*fd);
1698 file = PipeReadString(*fd);
1699 /* routine can be called with a NULL file_mgr_rec, use the
1700 * top level widget if this is the case.
1703 /* the object is copying/linking itself to the same folder. Want
1704 * to indicate the to the ok dialog and the building of the replace
1707 replace_rename_actionItems[0].data = (XtPointer)True;
1708 if(cb_data->file_mgr_rec)
1709 create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
1710 mode, directory, file,
1712 replace_renameActions, True);
1714 create_replace_rename_dialog(toplevel,
1715 mode, directory, file,
1717 replace_renameActions, True);
1722 case PIPEMSG_REPLACE_RENAME:
1723 /* filename collision: display replace/rename dialog */
1724 PipeRead(*fd, &mode, sizeof(int));
1725 directory = PipeReadString(*fd);
1726 file = PipeReadString(*fd);
1727 /* routine can be called with a NULL file_mgr_rec, use the
1728 * top level widget if this is the case.
1730 replace_rename_actionItems[0].data = (XtPointer)NULL;
1731 if(cb_data->file_mgr_rec)
1732 create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
1733 mode, directory, file,
1735 replace_renameActions, False);
1737 create_replace_rename_dialog(toplevel,
1738 mode, directory, file,
1740 replace_renameActions, False);
1745 case PIPEMSG_REPLACE_MERGE:
1746 /* filename collision: display replace/merge dialog */
1747 PipeRead(*fd, &mode, sizeof(int));
1748 directory = PipeReadString(*fd);
1749 file = PipeReadString(*fd);
1750 /* routine can be called with a NULL file_mgr_rec, use the
1751 * top level widget if this is the case.
1753 if(cb_data->file_mgr_rec)
1754 create_replace_merge_dialog(cb_data->file_mgr_rec->shell,
1755 mode, directory, file,
1757 replace_mergeActions);
1759 create_replace_merge_dialog(toplevel,
1760 mode, directory, file,
1762 replace_mergeActions);
1767 case PIPEMSG_MULTICOLLIDE_SAME:
1768 /* filename collision: display multicollide dialog */
1769 PipeRead(*fd, &mode, sizeof(int));
1770 PipeRead(*fd, &nSelected, sizeof(int));
1771 PipeRead(*fd, &nCollisions, sizeof(int));
1772 directory = PipeReadString(*fd);
1773 file = XtMalloc( MAX_PATH );
1774 fileList = (String *) XtMalloc(nCollisions * sizeof(String)); /* de- allocated in dialog's callback functions */
1775 for (i = 0; i < nCollisions; i++)
1777 fileList[i] = PipeReadString(*fd);
1779 /* routine can be called with a NULL file_mgr_rec, use the
1780 * top level widget if this is the case.
1783 /* the object is copying/linking itself to the same folder. Want
1784 * to indicate the to the ok dialog and the building of the replace
1787 multicollide_actionItems[0].data = (XtPointer)True;
1788 if(cb_data->file_mgr_rec)
1789 create_multicollide_dialog(cb_data->file_mgr_rec->shell,
1790 mode, nSelected, nCollisions,
1791 directory, fileList,
1793 multicollideActions, True);
1795 create_multicollide_dialog(toplevel,
1796 mode, nSelected, nCollisions,
1797 directory, fileList,
1799 multicollideActions, True);
1803 case PIPEMSG_MULTICOLLIDE:
1804 /* filename collision: display multicollide dialog */
1805 PipeRead(*fd, &mode, sizeof(int));
1806 PipeRead(*fd, &nSelected, sizeof(int));
1807 PipeRead(*fd, &nCollisions, sizeof(int));
1808 directory = PipeReadString(*fd);
1809 file = XtMalloc( MAX_PATH );
1810 fileList = (String *) XtMalloc(nCollisions * sizeof(String)); /* de-allocated in dialog's callback functions */
1811 for (i = 0; i < nCollisions; i++)
1813 fileList[i] = PipeReadString(*fd);
1815 /* routine can be called with a NULL file_mgr_rec, use the
1816 * top level widget if this is the case.
1818 multicollide_actionItems[0].data = (XtPointer)NULL;
1819 if(cb_data->file_mgr_rec)
1820 create_multicollide_dialog(cb_data->file_mgr_rec->shell,
1821 mode, nSelected, nCollisions,
1822 directory, fileList,
1824 multicollideActions, False);
1826 create_multicollide_dialog(toplevel,
1827 mode, nSelected, nCollisions,
1828 directory, fileList,
1830 multicollideActions, False);
1835 case PIPEMSG_TARGET_TIME:
1836 /* get the modify time and update the directory cache */
1837 PipeRead(*fd, &modify_time, sizeof(long));
1838 DirectoryModifyTime(cb_data->host, cb_data->directory, modify_time);
1841 case PIPEMSG_MOVE_TO_SAME_DIR:
1842 /* get the update index */
1843 PipeRead(*fd, &i, sizeof(int));
1844 cb_data->updates[i].operationStatus = True;
1845 DisplayDuplicateOpError((void *) cb_data,i);
1846 status = PIPEMSG_MOVE_TO_SAME_DIR;
1847 if(cb_data->callback_data)
1849 RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
1850 ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
1851 ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
1855 case PIPEMSG_FILE_MODIFIED:
1856 /* get the update index and modify time */
1857 PipeRead(*fd, &i, sizeof(int));
1858 PipeRead(*fd, &modify_time, sizeof(long));
1859 target_file = PipeReadString(*fd);
1860 DPRINTF (("PIPEMSG_FILE_MODIFIED %s\n", target_file));
1862 /* mark the file updated in the cached target directory */
1863 DirectoryFileModified(cb_data->host, cb_data->directory,
1866 if (cb_data->mode == MOVE_FILE)
1868 /* mark the file updated in the cached source directory */
1869 if (modify_time != 0)
1870 DirectoryModifyTime(cb_data->updates[i].host,
1871 cb_data->updates[i].directory,
1873 DirectoryFileModified(cb_data->updates[i].host,
1874 cb_data->updates[i].directory,
1875 cb_data->updates[i].file);
1877 cb_data->updates[i].operationStatus = True;
1878 XtFree(target_file); target_file = NULL;
1882 PipeRead(*fd, &rc, sizeof(int));
1887 fprintf(stderr, "Internal error in FileOpPipeCB: bad pipe_msg %d\n",
1895 char tmpDir[MAX_PATH];
1897 DPRINTF(("FileOpPipeCB: done, rc %d\n", rc));
1899 /* close the pipe and cancel the callback */
1900 close(cb_data->pipe_m2s);
1901 close(cb_data->pipe_s2m);
1905 *fd = (rc == 0)? 0: -1;
1907 /* arrange for modified directories to be updated */
1908 DirectoryEndModify(cb_data->host, cb_data->directory);
1910 /* Reposition the objects which have been modified */
1911 if(!cb_data->finish_callback && cb_data->file_mgr_data)
1915 /* Do this only if it is the current directory and Random placement
1917 if(cb_data->file_mgr_data->positionEnabled != RANDOM_OFF && strcmp(
1918 cb_data->directory,cb_data->file_mgr_data->current_directory)==0)
1920 file_set = (char **) XtCalloc(1,cb_data->file_count*sizeof(char *));
1921 for(i=0;i<cb_data->file_count;i++)
1923 if(cb_data->updates[i].operationStatus == True)
1924 file_set[actual_count++] = cb_data->updates[i].file;
1926 RepositionIcons(cb_data->file_mgr_data, file_set,actual_count,
1927 G_dropx, G_dropy, True);
1928 XtFree((char *)file_set);
1933 for(i = 0; i < desktop_data->numWorkspaces; i++)
1934 DeselectAllDTFiles(desktop_data->workspaceData[i]);
1936 for (i = 0; i < cb_data->file_count; i++)
1938 char fileName[MAX_PATH];
1940 /* Scroll the window to show the created object, since we
1941 cannot keep scrolling for each object we just do it for
1942 one object and we do it in case of Drag/Drop, but not
1943 for Select.MoveTo/CopyTo ... */
1945 if(!i && cb_data->callback_data == NULL)
1949 if(cb_data && cb_data->file_mgr_data)
1951 fmd = cb_data->file_mgr_data;
1952 fmd->scrollToThisDirectory = XtNewString(cb_data->directory);
1953 fmd->scrollToThisFile = XtNewString(cb_data->updates[i].file);
1956 if (cb_data->updates[i].first_index == i)
1958 if (cb_data->mode == MOVE_FILE)
1960 DirectoryEndModify(cb_data->updates[i].host,
1961 cb_data->updates[i].directory);
1962 if( strcmp( cb_data->updates[i].directory, "/" ) == 0 )
1965 sprintf( tmpDir, "%s", cb_data->updates[i].directory );
1968 if( cb_data->updates[i].host )
1969 XtFree( cb_data->updates[i].host );
1970 if( cb_data->updates[i].directory )
1971 XtFree( cb_data->updates[i].directory );
1972 if( cb_data->updates[i].app_man_dir )
1973 XtFree( cb_data->updates[i].app_man_dir );
1976 if( cb_data->mode == MOVE_FILE )
1978 sprintf( fileName, "%s/%s", tmpDir, cb_data->updates[i].file );
1979 if( cb_data->updates[i].operationStatus == True )
1981 if( status == PIPEMSG_MOVE_TO_SAME_DIR )
1983 RemoveIconFromWorkspace( fileName, cb_data->directory );
1985 else if( status != PIPEMSG_FILEOP_ERROR )
1987 ChangeWorkspaceIconLink(cb_data->file_mgr_data, fileName,
1988 cb_data->directory,tmpDir );
1990 /* If it is workspace drag and drop and the move operation
1991 is not because of Select.MoveTo menu option */
1993 if(initiating_view == NULL && cb_data->callback_data == NULL)
1995 sprintf( fileName, "%s/%s", cb_data->directory,
1996 cb_data->updates[i].file );
1997 DtEliminateDots(fileName);
1998 RemoveIconFromWorkspace( fileName, cb_data->directory );
2004 XtFree(cb_data->updates[i].file);
2009 /* call the callback routine */
2010 if (cb_data->finish_callback)
2011 (*cb_data->finish_callback)(cb_data->callback_data, rc);
2013 /* free the callback data */
2014 XtFree((char *)cb_data->updates);
2015 XtFree((char *)cb_data->directory);
2016 XtFree((char *)cb_data->host);
2017 XtFree(client_data);
2022 /*--------------------------------------------------------------------
2024 * Start the background process and set up callback for the pipe.
2025 *------------------------------------------------------------------*/
2035 BufferInfo *buffer_set,
2037 unsigned int modifiers,
2038 DesktopRec *desktopWindow,
2039 void (*finish_callback)(),
2040 XtPointer callback_data)
2042 static char *pname = "_FileMoveCopy";
2044 FileOpCBData *cb_data;
2048 char *source_dir = NULL;
2049 char *source_file = NULL;
2055 struct timeval now, select_end, select_timeout;
2056 Boolean operation_done;
2060 /* Determine the type of operation: move, copy, or link */
2061 /* or creating buffers */
2062 if (buffer_set != NULL)
2068 modifiers &= ~Button2Mask;
2069 if (modifiers == ShiftMask)
2071 else if (modifiers == ControlMask)
2077 /* set up the callback data structure */
2078 cb_data = XtNew(FileOpCBData);
2079 cb_data->desktop = (desktopWindow != NULL);
2080 if (cb_data->desktop)
2082 cb_data->file_mgr_data = NULL;
2083 cb_data->file_mgr_rec = NULL;
2084 cb_data->file_view_data = (FileViewData *)data;
2085 cb_data->desktopWindow = desktopWindow;
2091 cb_data->file_mgr_data = (FileMgrData *)data;
2092 cb_data->file_mgr_rec =
2093 (FileMgrRec *) ((FileMgrData *)data)->file_mgr_rec;
2097 cb_data->file_mgr_data = NULL;
2098 cb_data->file_mgr_rec = NULL;
2100 cb_data->file_view_data = NULL;
2101 cb_data->desktopWindow = NULL;
2103 cb_data->mode = mode;
2104 cb_data->host = XtNewString(host);
2105 cb_data->directory = XtNewString(directory);
2106 cb_data->finish_callback = finish_callback;
2107 cb_data->callback_data = callback_data;
2110 /* mark the target directory as being modified in the directory cache */
2111 DirectoryBeginModify(host, directory);
2113 /* make a list of the operations to be done */
2114 /* Allocate memory for the DirUpdateStructure */
2115 cb_data->file_count = file_count;
2117 updates = (DirUpdate *)XtMalloc(file_count * sizeof(DirUpdate));
2119 /* Determine whether we are dealing with files or buffers */
2120 /* This affects how the updates structure is initialized */
2121 if (mode == MAKE_BUFFER)
2123 for (i=0; i< file_count; i++)
2125 /* just simply set the the updates structure with */
2126 /* the passed in file names */
2127 updates[i].file = XtNewString(file_set[i]);
2128 updates[i].bufferInfo.buf_ptr = buffer_set[i].buf_ptr;
2129 updates[i].bufferInfo.size = buffer_set[i].size;
2131 /* set unused updates fields to NOOP values */
2132 updates[i].time_sent = FALSE;
2133 updates[i].first_index = 0;
2134 updates[i].host = NULL;
2135 updates[i].directory = NULL;
2136 updates[i].app_man_dir = NULL;
2141 /* Seperate file names, directories, and hosts */
2142 /* when dealing with real files */
2143 for (i=0; i< file_count; i++)
2145 /* get the name of the source directory */
2146 ptr = strrchr(file_set[i], '/');
2149 if (ptr == file_set[i])
2154 source_dir = file_set[i];
2156 source_file = ptr + 1;
2160 source_dir = strdup(".");
2161 source_file = file_set[i];
2164 /* see if this directory is already in the list */
2165 for (j = 0; j < i; j++)
2166 if (strcmp(updates[j].host, host_set[i]) == 0 &&
2167 strcmp(updates[j].directory, source_dir) == 0)
2171 { /* already in the list */
2172 updates[i].host = updates[j].host;
2173 updates[i].directory = updates[j].directory;
2174 updates[i].app_man_dir = updates[j].app_man_dir;
2177 { /* not yet in the list */
2178 updates[i].host = XtNewString(host_set[i]);
2179 updates[i].directory = XtNewString(source_dir);
2180 updates[i].app_man_dir = NULL;
2185 if (((FileMgrData *)data)->toolbox)
2186 updates[i].app_man_dir =
2187 XtNewString(((FileMgrData *)data)->restricted_directory);
2191 /* mark the directory as being modified in the directory cache */
2192 if (mode == MOVE_FILE)
2193 DirectoryBeginModify(updates[i].host, updates[i].directory);
2195 updates[i].first_index = j;
2196 updates[i].time_sent = False;
2197 updates[i].operationStatus = False;
2198 updates[i].file = XtNewString(source_file);
2200 if (NULL != ptr) *ptr = '/';
2209 /* fork the process that does the actual work */
2213 DirectoryAbortModify(host, directory);
2214 for (i=0; i<file_count; i++)
2215 if (mode == MOVE_FILE && updates[i].first_index == i)
2216 DirectoryAbortModify(updates[i].host, updates[i].directory);
2219 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
2220 pname, getppid(), getpid(), errno, strerror(errno));
2226 DBGFORK(("%s: child forked, m2s %d s2m %d\n",
2227 pname, pipe_m2s[0], pipe_s2m[1]));
2229 close(pipe_m2s[1]); /* won't write to pipe_m2s */
2230 close(pipe_s2m[0]); /* won't read from pipe_s2m */
2232 if (desktopWindow != NULL)
2233 rc = FileMoveCopyProcessDesktop(pipe_s2m[1], pipe_m2s[0],
2234 directory, host, updates, file_count,
2235 mode, desktopWindow);
2237 rc = FileMoveCopyProcess(pipe_s2m[1], pipe_m2s[0], to_file, directory,
2238 host, updates, file_count, mode, NULL);
2240 DBGFORK(("%s: child exiting\n", pname));
2244 DBGFORK(("%s: forked child<%d>, m2s %d, s2m %d\n",
2245 pname, pid, pipe_m2s[1], pipe_s2m[0]));
2248 /* parent: set up callback to get the pipe data */
2249 close(pipe_m2s[0]); /* won't read from pipe_m2s */
2250 close(pipe_s2m[1]); /* won't write to pipe_s2m */
2252 cb_data->pipe_m2s = pipe_m2s[1];
2253 cb_data->pipe_s2m = pipe_s2m[0];
2254 cb_data->mode = mode;
2256 cb_data->child = pid;
2260 * We wait a certain amount of time for the background process to finish.
2261 * If it doesn't finish within that time, we do the rest asynchronously.
2264 /* set up fd set for select */
2265 FD_ZERO(&select_fds);
2268 /* compute until what time we want to wait */
2269 gettimeofday(&select_end, NULL);
2270 select_end.tv_sec += FILE_MOVE_COPY_WAIT_TIME;
2272 operation_done = False;
2275 /* determine how much time is left */
2276 gettimeofday(&now, NULL);
2277 select_timeout.tv_sec = select_end.tv_sec - now.tv_sec;
2278 select_timeout.tv_usec = select_end.tv_usec - now.tv_usec;
2279 if (select_timeout.tv_usec < 0)
2281 select_timeout.tv_sec--;
2282 select_timeout.tv_usec += 1000000;
2285 if ((int) select_timeout.tv_sec < 0)
2287 /* check if our time is up */
2288 DPRINTF(("FileMoveCopy: timed out; adding input callback\n"));
2289 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
2290 pipe_s2m[0], (XtPointer)XtInputReadMask,
2291 FileOpPipeCB, (XtPointer)cb_data);
2296 FD_SET(fd, &select_fds);
2297 #if defined(__hpux) && (OSMAJORVERSION <= 10) && (OSMINORVERSION < 2)
2298 rc = select(fd + 1, (int *)&select_fds, NULL, NULL, &select_timeout);
2300 rc = select(fd + 1, &select_fds, NULL, NULL, &select_timeout);
2302 if (rc < 0 && errno != EINTR)
2304 perror("select failed in FileMoveCopy");
2309 /* call FileOpPipeCB to read & process the data from the pipe */
2310 FileOpPipeCB((XtPointer)cb_data, &fd, NULL);
2311 DPRINTF(("FileMoveCopy: FileOpPipeCB -> fd = %d\n", fd));
2314 * If the background process is done, FileOpPipeCB sets fd
2315 * to zero (in case of success) or -1 (in case of failure).
2319 operation_done = (fd == 0);
2325 return operation_done;
2329 /*--------------------------------------------------------------------
2330 * FileMoveCopy, FileMoveCopyDesktop
2331 * External entry points for invoking _FileMoveCopy
2332 *------------------------------------------------------------------*/
2336 FileMgrData *file_mgr_data,
2343 unsigned int modifiers,
2344 void (*finish_callback)(),
2345 XtPointer callback_data)
2347 return _FileMoveCopy( (XtPointer)file_mgr_data, to_file, directory, host,
2348 host_set, file_set, NULL, file_count, modifiers, NULL,
2349 finish_callback, callback_data);
2354 FileMoveCopyDesktop(
2355 FileViewData *file_view_data,
2360 unsigned int modifiers,
2361 DesktopRec *desktopWindow,
2362 void (*finish_callback)(),
2363 XtPointer callback_data)
2365 return _FileMoveCopy ((XtPointer)file_view_data,
2380 /*====================================================================
2383 * Run a background process to rename an object.
2385 *==================================================================*/
2387 /*--------------------------------------------------------------------
2388 * ChangeIconNameProcess:
2389 * Main routine of the background process
2390 *------------------------------------------------------------------*/
2393 ChangeIconNameProcess(
2396 char *directory_name,
2400 char * full_name, * old_full_name, *dir_path;
2401 struct stat stat_buf;
2406 Tt_status tt_status;
2408 /* Check for uniqueness */
2409 full_name = ResolveLocalPathName(host_name, directory_name, new_name, home_host_name, &tt_status);
2410 if ( TT_OK != tt_status )
2412 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2413 pipe_msg = PIPEMSG_FILEOP_ERROR;
2414 write(pipe_fd, &pipe_msg, sizeof(short));
2419 if (lstat(full_name, &stat_buf) == 0)
2421 /* Name is not unique */
2422 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2423 pipe_msg = PIPEMSG_EXIST_ERROR;
2424 write(pipe_fd, &pipe_msg, sizeof(short));
2431 /* send a modified message back through the pipe */
2433 dir_path = ResolveLocalPathName(host_name, directory_name, NULL, home_host_name, &tt_status);
2434 if( TT_OK != tt_status )
2436 DPRINTF(("ChadengeIconNameProcess: sending exist error\n"));
2437 pipe_msg = PIPEMSG_FILEOP_ERROR;
2438 write(pipe_fd, &pipe_msg, sizeof(short));
2444 if (stat(dir_path, &stat_buf) == 0)
2445 modify_time = stat_buf.st_mtime;
2448 /* rename the file */
2449 old_full_name = ResolveLocalPathName(host_name, directory_name, old_name, home_host_name, &tt_status);
2450 if( TT_OK != tt_status )
2452 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2453 pipe_msg = PIPEMSG_FILEOP_ERROR;
2454 write(pipe_fd, &pipe_msg, sizeof(short));
2459 success = FileManip((Widget) (intptr_t) pipe_fd, MOVE_FILE, old_full_name, full_name, TRUE,
2460 FileOpError, True, NOT_DESKTOP);
2461 XtFree( old_full_name );
2462 /* send a 'done' msg through the pipe */
2463 rc = success? 0: -1;
2466 pipe_msg = PIPEMSG_FILE_MODIFIED;
2467 write(pipe_fd, &pipe_msg, sizeof(short));
2468 write(pipe_fd, &modify_time, sizeof(long));
2470 DPRINTF(("ChangeIconNameProcess: sending DONE, rc %d\n", rc));
2471 pipe_msg = PIPEMSG_DONE;
2472 write(pipe_fd, &pipe_msg, sizeof(short));
2473 write(pipe_fd, &rc, sizeof(int));
2475 PipeWriteString(pipe_fd, full_name);
2476 XtFree( full_name );
2481 /*--------------------------------------------------------------------
2483 * Read and process data sent through the pipe.
2484 *------------------------------------------------------------------*/
2488 XtPointer client_data,
2492 ChangeIconCBData *cb_data = (ChangeIconCBData *)client_data;
2493 FileViewData *file_view_data = cb_data->file_view_data;
2494 DesktopRec *desktopWindow = cb_data->desktopWindow;
2497 DirectorySet *directory_set;
2498 FileMgrData *file_mgr_data = NULL;
2499 FileMgrRec *file_mgr_rec;
2503 char *title, *err_msg, *err_arg;
2509 Boolean desktop_changed;
2511 /* get widget for error messages */
2512 if (cb_data->desktop)
2514 msg_widget = XtParent(cb_data->w);
2518 directory_set = (DirectorySet *)file_view_data->directory_set;
2519 file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
2520 file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
2521 msg_widget = file_mgr_rec->file_window;
2524 /* read the msg from the pipe */
2526 n = PipeRead(*fd, &pipe_msg, sizeof(short));
2527 DPRINTF(("ChangeIconPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
2529 if (pipe_msg == PIPEMSG_FILE_MODIFIED)
2531 /* get modify time */
2532 PipeRead(*fd, &modify_time, sizeof(long));
2534 /* mark the old & new files as modified in the directory cache */
2535 if (modify_time != 0)
2536 DirectoryModifyTime(cb_data->host_name, cb_data->directory_name,
2538 DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
2540 DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
2545 if (pipe_msg == PIPEMSG_EXIST_ERROR)
2547 /* Name is not unique */
2548 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2549 if (cb_data->desktop)
2551 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.");
2552 err_msg = XtNewString(tmpStr);
2555 err_msg = XtNewString(GETMESSAGE(9,9, "A file with this name already exists.\nPlease choose a different name."));
2557 _DtMessage (msg_widget, title, err_msg, NULL, HelpRequestCB);
2562 else if (pipe_msg == PIPEMSG_FILEOP_ERROR)
2564 /* the rename failed */
2565 PipeRead(*fd, &rc, sizeof(int));
2566 err_msg = PipeReadString(*fd);
2567 err_arg = PipeReadString(*fd);
2568 FileOperationError(msg_widget, err_msg, err_arg);
2573 else if (pipe_msg == PIPEMSG_DONE)
2575 /* get the return code */
2576 PipeRead(*fd, &rc, sizeof(int));
2579 /* the rename was successful */
2580 full_name = PipeReadString(*fd);
2582 /* All went well, destroy the text field */
2583 XtUnmanageChild(cb_data->w);
2584 XtDestroyWidget(cb_data->w);
2586 /* Force the icon label to be updated immediately */
2587 if (cb_data->desktop)
2589 XmProcessTraversal(desktopWindow->iconGadget, XmTRAVERSE_CURRENT);
2590 desktopWindow->text = NULL;
2591 /* we'll catch this icon label in the loop after the else */
2595 file_mgr_data->renaming = NULL;
2597 label = XmStringCreateLocalized(cb_data->new_name);
2598 XtSetArg(args[0], XmNstring, label);
2599 XtSetValues(file_view_data->widget, args, 1);
2600 XmStringFree(label);
2601 XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
2602 XmUpdateDisplay (file_mgr_rec->file_window);
2605 * To prevent the positional data from becoming disassociated with
2606 * this file, we need to change the name in the positional data
2609 for (i = 0; i < file_mgr_data->num_objects; i++)
2611 if (strcmp(cb_data->old_name,
2612 file_mgr_data->object_positions[i]->name) == 0)
2615 XtFree(file_mgr_data->object_positions[i]->name);
2616 file_mgr_data->object_positions[i]->name =
2617 XtNewString(cb_data->new_name);
2624 * Check all desktop windows to see if they were linked to
2625 * the file we just renamed. If so, we need to change the
2626 * link in .dt/Desktop that points to it.
2628 * Note: We could do this in a background process, but we assume
2629 * that .dt/Desktop is local or, if it's remote and the remote server
2630 * is down, the user is screwed anyway. So we assume it's ok to do
2631 * blocking operations on .dt/Desktop in the main process.
2632 * Hence we go for the simpler solution here.
2634 desktop_changed = False;
2635 for (i = 0; i < desktop_data->numIconsUsed; i++)
2637 desktopWindow = desktop_data->desktopWindows[i];
2639 if (strcmp(cb_data->host_name, desktopWindow->host) == 0 &&
2640 strcmp(cb_data->directory_name, desktopWindow->dir_linked_to) == 0
2641 && strcmp(cb_data->old_name, desktopWindow->file_name) == 0)
2645 /* Force the icon label to be updated immediately */
2646 label = XmStringCreateLocalized(cb_data->new_name);
2647 XtSetArg(args[0], XmNstring, label);
2648 XtSetValues(desktopWindow->iconGadget, args, 1);
2649 XmStringFree(label);
2651 XtFree(desktopWindow->file_name);
2652 desktopWindow->file_name = XtNewString(cb_data->new_name);
2654 XtFree(desktopWindow->file_view_data->file_data->file_name);
2655 desktopWindow->file_view_data->file_data->file_name =
2656 XtNewString(cb_data->new_name);
2657 if( strcmp( desktopWindow->title, cb_data->old_name ) == 0 )
2659 XtFree( desktopWindow->title );
2660 desktopWindow->title = XtNewString( cb_data->new_name );
2663 GenerateShape(desktopWindow);
2665 RegisterIconDropsDT(desktopWindow);
2666 XmUpdateDisplay (desktopWindow->iconGadget);
2668 desktop_changed = True;
2672 if (desktop_changed)
2674 SaveDesktopInfo(NORMAL_RESTORE);
2682 fprintf(stderr, "Internal error in ChangeIconPipeCB: bad pipe_msg %d\n",
2685 /* arrange for the modified directory to be updated */
2686 DirectoryEndModify(cb_data->host_name, cb_data->directory_name);
2688 /* close the pipe and cancel the callback */
2692 /* free callback data */
2693 XtFree(cb_data->host_name);
2694 XtFree(cb_data->directory_name);
2695 XtFree(cb_data->old_name);
2696 XtFree(cb_data->new_name);
2697 XtFree((char *)cb_data);
2701 /*--------------------------------------------------------------------
2703 * Start the background process and set up callback for the pipe.
2704 *------------------------------------------------------------------*/
2710 FileViewData *file_view_data,
2711 DesktopRec *desktopWindow,
2713 char *directory_name)
2715 static char *pname = "_ChangeIconName";
2716 ChangeIconCBData *cb_data;
2728 int dirNameLength = strlen (directory_name);
2729 int maxFileNameLength = pathconf (directory_name, _PC_NAME_MAX);
2733 /* get the new name */
2734 XtSetArg(args[0], XmNvalue, &input_name);
2735 XtSetArg(args[1], XmNuserData, &old_name);
2736 XtGetValues(w, args, 2);
2738 new_name = (char *)_DtStripSpaces(XtNewString(input_name));
2739 length = strlen (new_name);
2742 /* new name must be a simple name, no path */
2744 if (DtStrchr (new_name, '/') != NULL)
2745 msg = XtNewString(GetSharedMessage(LOCAL_RENAME_ONLY_ERROR));
2746 #ifdef _CHECK_FOR_SPACES
2747 else if (DtStrchr (new_name, ' ') != NULL ||
2748 DtStrchr (new_name, '\t') != NULL)
2750 msg = XtNewString(GetSharedMessage(NO_SPACES_ALLOWED_ERROR));
2753 else if (length == 0 || strcmp(new_name, old_name) == 0)
2755 /* Noop; simply remove the text field */
2756 XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
2760 UnpostDTTextField();
2764 DirectorySet *directory_set =
2765 (DirectorySet *)file_view_data->directory_set;
2766 FileMgrData *file_mgr_data =
2767 (FileMgrData *)directory_set->file_mgr_data;
2768 FileMgrRec *file_mgr_rec =
2769 (FileMgrRec *)file_mgr_data->file_mgr_rec;
2770 file_mgr_rec->menuStates |= RENAME;
2771 UnpostTextField( file_mgr_data );
2772 file_mgr_data->renaming = NULL;
2776 /* Ensure the new name has length less than or equal to the maximum
2777 length that the system allows.
2778 If maxFileNameLength == -1 the file system is not supporting POSIX, use MAXNAMLEN
2780 else if( maxFileNameLength < -1 || ( maxFileNameLength == -1 && ( length > MAXNAMLEN || length + dirNameLength > MAX_PATH ) ) || ( maxFileNameLength > 0 && length > maxFileNameLength ) )
2782 msg = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2788 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2789 _DtMessage (XtParent (w), title, msg, NULL, HelpRequestCB);
2796 /* Check to see if the file has a representitive on the Desktop. */
2797 if (desktopWindow == NULL)
2799 for (i = 0; i < desktop_data->numIconsUsed; i++)
2801 if (strcmp(host_name,
2802 desktop_data->desktopWindows[i]->host) == 0 &&
2803 strcmp(directory_name,
2804 desktop_data->desktopWindows[i]->dir_linked_to) == 0 &&
2805 strcmp(old_name, desktop_data->desktopWindows[i]->
2806 file_view_data->file_data->file_name) == 0)
2808 desktopWindow = desktop_data->desktopWindows[i];
2814 if (desktopWindow != NULL)
2817 * There is a representation of this file on the desktop:
2818 * check if the there are any objects which match the new_name
2820 for (j = 0; j < desktop_data->numIconsUsed; j++)
2822 if (strcmp(new_name, desktop_data->desktopWindows[j]->
2823 file_view_data->file_data->file_name) == 0)
2825 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2827 tmpStr = GETMESSAGE(28,9, "An object with this name already exists on the Workspace.\nPlease choose a different name.");
2829 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.");
2830 msg = XtNewString(tmpStr);
2831 _DtMessage(XtParent (w), title, msg, NULL, HelpRequestCB);
2841 * Now we are ready to start the background process
2842 * that does the actual rename.
2845 /* set up callback data */
2846 cb_data = XtNew(ChangeIconCBData);
2848 cb_data->desktop = desktop;
2849 cb_data->file_view_data = file_view_data;
2850 cb_data->desktopWindow = desktopWindow;
2851 cb_data->host_name = XtNewString(host_name);
2852 cb_data->directory_name = XtNewString(directory_name);
2853 cb_data->old_name = XtNewString(old_name);
2854 cb_data->new_name = new_name;
2856 /* mark the directory as being modified in the directory cache */
2857 DirectoryBeginModify(host_name, directory_name);
2862 /* fork the process that does the actual work */
2866 DirectoryAbortModify(host_name, directory_name);
2868 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
2869 pname, getppid(), getpid(), errno, strerror(errno));
2875 DBGFORK(("%s: child forked, pipe %d\n", pname, pipe_fd[1]));
2877 close(pipe_fd[0]); /* child won't read from the pipe */
2879 rc = ChangeIconNameProcess(pipe_fd[1], host_name, directory_name,
2880 old_name, new_name);
2883 DBGFORK(("%s: child exiting\n", pname));
2888 DBGFORK(("%s: forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
2891 /* parent: set up callback to get the pipe data */
2892 close(pipe_fd[1]); /* parent won't write the pipe */
2894 cb_data->child = pid;
2896 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
2897 pipe_fd[0], (XtPointer)XtInputReadMask,
2898 ChangeIconPipeCB, (XtPointer)cb_data);
2905 XtPointer client_data,
2906 XmTextVerifyCallbackStruct * call_data)
2908 int value, size, increment, page;
2910 FileMgrData *file_mgr_data = (FileMgrData *)client_data;
2911 FileMgrRec *file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
2912 DirectorySet *directory_set = (DirectorySet *)(file_mgr_data->renaming->directory_set);
2914 if (call_data->reason == XmCR_MODIFYING_TEXT_VALUE ||
2915 call_data->reason == XmCR_MOVING_INSERT_CURSOR )
2918 /* x1 - x value of the text widget with respect to scroll window
2919 x2,y2 - x,y values of the cursor position (new) w.r.t text widget
2920 x3,y3 - x,y values of the cursor position (previous) w.r.t textW
2922 Position x1,x2,y2,x3,y3;
2923 /* width of the text widget */
2924 Dimension stringWidth;
2926 XtSetArg(args[0],XmNx,&x1);
2927 XtGetValues(w,args,1);
2929 if(XtIsManaged(file_mgr_rec->vertical_scroll_bar))
2930 SWwidth=(file_mgr_rec->scroll_window->core.width -
2931 file_mgr_rec->vertical_scroll_bar->core.width);
2933 SWwidth=file_mgr_rec->scroll_window->core.width;
2935 XmTextFieldPosToXY(w,call_data->newInsert,&x2,&y2);
2936 XmTextFieldPosToXY(w,call_data->currInsert,&x3,&y3);
2938 XtSetArg(args[0],XmNwidth,&stringWidth);
2939 XtGetValues(w,args,1);
2941 printf("\n x2=%d x1=%d x3=%d\n",x2,x1,x3);
2943 if ( (Dimension)(call_data->newInsert) < stringWidth )
2945 if( XtIsManaged(file_mgr_rec->horizontal_scroll_bar) )
2947 XmScrollBarGetValues( file_mgr_rec->horizontal_scroll_bar,
2948 &value, &size, &increment, &page);
2950 printf("\n value = %d",value);
2952 /* case where cursor is moved forward */
2956 XtSetArg (args[0], XmNmaximum, &max);
2957 XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
2958 if( (value < (max-size)) &&
2959 ((x1+x2) - value > 0 ) &&
2960 ( (Position)(((x1+x2) - value) +
2961 file_mgr_rec->vertical_scroll_bar->core.width) > (Position) SWwidth ) )
2963 if( (value+(x2-x3)) > (max-size) )
2967 XmScrollBarSetValues(
2968 file_mgr_rec->horizontal_scroll_bar,
2969 value, size, increment, page,True
2973 /* case where cursor is moved in reverse direction */
2974 else if( (x2-x3) < 0 )
2977 XtSetArg (args[0], XmNminimum, &min);
2978 XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
2979 if( (value > min) && ((Position)(x1+x3) < (Position)(value+
2980 file_mgr_rec->vertical_scroll_bar->core.width)) )
2982 if( (x2 <= 0) || ((value - (x3-x2)) < min) )
2986 XmScrollBarSetValues(file_mgr_rec->horizontal_scroll_bar,
2987 value, size, increment, page,True
2995 _ChangeIconName (w, False, file_mgr_data->renaming, NULL,
2996 file_mgr_data->host, directory_set->name);
3003 XtPointer client_data,
3004 XtPointer call_data)
3006 DesktopRec * desktopWindow = (DesktopRec *)client_data;
3008 _ChangeIconName (w, True, desktopWindow->file_view_data, desktopWindow,
3009 desktopWindow->host, desktopWindow->dir_linked_to);
3013 /*====================================================================
3016 * Run a background process to create a file or directory.
3018 *==================================================================*/
3020 /*--------------------------------------------------------------------
3022 * Build a host, directory, and file name path to be used as the
3023 * destination of a create, copy or move operation.
3024 *------------------------------------------------------------------*/
3037 strcpy(to_host, from_host);
3039 if (strncmp (new_name, "/", 1) == 0)
3041 strcpy(to_dir, new_name);
3045 if (strcmp(to_dir, "/") == 0)
3046 sprintf(to_dir, "%s%s", from_dir, new_name);
3048 sprintf(to_dir, "%s/%s", from_dir, new_name);
3051 ptr = strrchr(to_dir, '/');
3053 strcpy(to_file, ptr + 1);
3057 /*--------------------------------------------------------------------
3059 * Main routine of background process for MakeFile
3060 *------------------------------------------------------------------*/
3071 struct stat stat_buf;
3077 Tt_status tt_status;
3079 /* assume success */
3082 /* get the full name of the file/dir to be created */
3083 to = ResolveLocalPathName(to_host, to_dir, to_file, home_host_name, &tt_status);
3087 /* check if a file/dir with the same name already exists */
3088 else if (lstat (to, &stat_buf) == 0)
3091 /* now create the file/dir */
3094 /* send a modified message back through the pipe */
3096 dir_path = ResolveLocalPathName(to_host, to_dir, NULL, home_host_name, &tt_status);
3097 if (stat(dir_path, &stat_buf) == 0)
3098 modify_time = stat_buf.st_mtime;
3101 pipe_msg = PIPEMSG_FILE_MODIFIED;
3102 write(pipe_fd, &pipe_msg, sizeof(short));
3103 write(pipe_fd, &modify_time, sizeof(long));
3106 if (type == DtDIRECTORY)
3108 if (mkdir (to, (int) DtFILE_DIR_CREATION_MASK) != 0)
3116 mode = DtFILE_DATA_CREATION_MASK;
3118 mode = DtFILE_OTHER_CREATION_MASK;
3120 if ((fnew = creat(to, (int) mode)) < 0)
3127 /* send a 'done' msg through the pipe */
3128 pipe_msg = PIPEMSG_DONE;
3129 DPRINTF(("MakeFileProcess: sending DONE, rc %d\n", rc));
3130 write(pipe_fd, &pipe_msg, sizeof(short));
3131 write(pipe_fd, &rc, sizeof(int));
3132 PipeWriteString(pipe_fd, to);
3140 /*--------------------------------------------------------------------
3142 * Read and process data sent through the pipe.
3143 *------------------------------------------------------------------*/
3147 XtPointer client_data,
3151 MakeFileCBData *cb_data = (MakeFileCBData *)client_data;
3158 /* read the msg from the pipe */
3160 n = PipeRead(*fd, &pipe_msg, sizeof(short));
3162 if (pipe_msg == PIPEMSG_FILE_MODIFIED)
3164 /* get modify time */
3165 PipeRead(*fd, &modify_time, sizeof(long));
3167 /* mark the file updated in the directory cache */
3168 if (modify_time != 0)
3169 DirectoryModifyTime(cb_data->to_host, cb_data->to_dir, modify_time);
3170 DirectoryFileModified(cb_data->to_host, cb_data->to_dir,
3175 if (pipe_msg == PIPEMSG_DONE)
3177 PipeRead(*fd, &rc, sizeof(int));
3178 full_name = PipeReadString(*fd);
3182 fprintf(stderr, "Internal error in MakeFilePipeCB: bad pipe_msg %d\n",
3188 DPRINTF(("MakeFilePipeCB: n %d, pipe_msg %d, rc %d\n", n, pipe_msg, rc));
3190 /* arrange for the modified directory to be updated */
3191 DirectoryEndModify(cb_data->to_host, cb_data->to_dir);
3193 /* close the pipe and cancel the callback */
3197 /* Store away the newly created file so we later on we can
3201 MakeFileDoneData * data = (MakeFileDoneData *)cb_data->callback_data;
3202 DialogCallbackStruct * call_struct = data->call_struct;
3203 FileMgrData * file_mgr_data = call_struct->file_mgr_data;
3205 file_mgr_data->scrollToThisDirectory = cb_data->to_dir;
3206 file_mgr_data->scrollToThisFile = cb_data->to_file;
3209 /* call the callback routine */
3210 if (cb_data->finish_callback)
3211 (*cb_data->finish_callback)(cb_data->callback_data, full_name, rc);
3213 /* free callback data */
3215 XtFree(cb_data->to_host);
3217 /* Don't free to_dir and to_file. We used this to remember
3218 which file so later on we can scroll to it.
3219 XtFree(cb_data->to_dir);
3220 XtFree(cb_data->to_file);
3223 XtFree((char *)cb_data);
3227 /*--------------------------------------------------------------------
3229 * Start the background process and set up callback for the pipe.
3230 *------------------------------------------------------------------*/
3236 char *directory_name,
3239 void (*finish_callback)(),
3240 XtPointer callback_data)
3242 static char *pname = "MakeFile";
3243 MakeFileCBData *cb_data;
3244 char to_host[MAX_PATH];
3245 char to_dir[MAX_PATH];
3246 char to_file[MAX_PATH];
3251 /* get host & path of the target file */
3252 GetTarget(host_name, directory_name, new_name, to_host, to_dir, to_file);
3254 /* mark the target directory as being modified in the directory cache */
3255 DirectoryBeginModify(to_host, to_dir);
3257 /* parent: set up callback to get the pipe data */
3258 cb_data = XtNew(MakeFileCBData);
3259 cb_data->to_host = XtNewString(to_host);
3260 cb_data->to_dir = XtNewString(to_dir);
3261 cb_data->to_file = XtNewString(to_file);
3262 cb_data->finish_callback = finish_callback;
3263 cb_data->callback_data = callback_data;
3268 /* fork the process that does the actual work */
3272 DirectoryAbortModify(to_host, to_dir);
3274 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
3275 pname, getppid(), getpid(), errno, strerror(errno));
3282 DBGFORK(("%s: child forked, pipe %d\n", pname, pipe_fd[1]));
3284 close(pipe_fd[0]); /* child won't read from the pipe */
3286 rc = MakeFileProcess(pipe_fd[1], to_host, to_dir, to_file, type);
3289 DBGFORK(("%s: child exiting\n", pname));
3294 DBGFORK(("%s: forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
3296 /* parent: set up callback to get the pipe data */
3297 close(pipe_fd[1]); /* parent won't write the pipe */
3299 cb_data->child = pid;
3301 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
3302 pipe_fd[0], (XtPointer)XtInputReadMask,
3303 MakeFilePipeCB, (XtPointer)cb_data);
3307 /*=============================================================
3309 * The following routines handle the creation of files from
3310 * buffers: MakeFilesFromBuffers and MakeFilesFromBuffersDT
3313 *=============================================================*/
3316 MakeFilesFromBuffers(
3317 FileMgrData *file_mgr_data,
3322 BufferInfo *buffer_set,
3324 void (*finish_callback)(),
3325 XtPointer callback_data)
3327 return _FileMoveCopy ((XtPointer)file_mgr_data, NULL, directory, host,
3328 host_set, file_set, buffer_set, num_of_buffers,
3329 0, NULL, finish_callback, callback_data);
3334 MakeFilesFromBuffersDT(
3335 FileViewData *file_view_data,
3339 BufferInfo *buffer_set,
3341 DesktopRec *desktopWindow,
3342 void (*finish_callback)(),
3343 XtPointer callback_data)
3345 return _FileMoveCopy ((XtPointer)file_view_data, NULL, directory,
3347 host_set, file_set, buffer_set, num_of_buffers,
3348 0, desktopWindow, finish_callback, callback_data);
3352 /*====================================================================
3354 * CreateFileFromBuffer
3355 * Routine to create a file from a buffer
3357 *==================================================================*/
3361 CreateFileFromBuffer(int pipe_s2m,
3363 char *fully_qualified_name,
3370 Boolean BufferIsExecutable=FALSE;
3371 char *err_msg, *err_arg, *tmpStr;
3372 char *format_str, *strerror_str;
3373 int format_param_len=20;
3379 /* Set the permissions depending if buffer is a */
3380 /* file or an execuatable */
3381 if (_DtIsBufferExecutable(buffer,size))
3383 mode = S_IRUSR | S_IWUSR | S_IXUSR |
3384 S_IRGRP | S_IWGRP | S_IXGRP |
3385 S_IROTH | S_IWOTH | S_IXOTH;
3389 mode = S_IRUSR | S_IWUSR |
3394 /* Create the target file */
3395 if ((fnew = open(fully_qualified_name, O_CREAT| O_WRONLY, mode)) < 0)
3397 DPRINTF(("CreateBufferFromFile: Could not create %s\n",
3398 fully_qualified_name));
3404 /* Write the buffer to the target file */
3405 if ((rc = write(fnew, buffer, size)) < 0 )
3407 DPRINTF (("CreateBufferFromFile: Could not write buffer to %s\n",
3408 fully_qualified_name));
3414 DPRINTF (("CreateBuffeFromFile: Target file %s created\n",
3415 fully_qualified_name));
3425 tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
3426 err_msg = XtNewString(tmpStr);
3427 err_arg = XtNewString(fully_qualified_name);
3429 DPRINTF (("CreateBufferFromFile: EACCESS errno is %d\n",errno));
3432 err_msg = strerror(savedError);
3435 DPRINTF (("CreateBufferFromFile: %s\n", err_msg));
3438 /* Write error message on pipe so */
3439 /* that the parent process will */
3440 /* display a dialog */
3441 PipeWriteErrmsg(pipe_s2m, rc, err_msg, err_arg);
3442 if (err_msg) XtFree(err_msg);
3443 if (err_arg) XtFree(err_arg);
3454 * DisplayDuplicateOpError - Used in FileOpPipeCallback when a duplicate
3455 * operation like move/copy/link a file onto the same file is performed,
3456 * this routine gets called and displays an error message.
3460 DisplayDuplicateOpError(
3461 FileOpCBData *cb_data,
3465 char *msgptr,*err_msg,*title,*tchar;
3466 Widget dialogwidget;
3468 if (cb_data->mode == MOVE_FILE)
3470 if(cb_data->callback_data == NULL)
3471 if(initiating_view == NULL)
3475 title = XtCalloc(1,strlen(GETMESSAGE(9,73,"Move"))+
3476 strlen(GETMESSAGE(9,94,"Error"))+5);
3477 tchar = XtNewString(GETMESSAGE(9,73,"Move"));
3478 sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3480 err_msg = GETMESSAGE(11,135,"Cannot move object %s onto itself");
3483 else if (cb_data->mode == COPY_FILE)
3485 title = XtCalloc(1,strlen(GETMESSAGE(9,72,"Copy"))+
3486 strlen(GETMESSAGE(9,94,"Error"))+5);
3487 tchar = XtNewString(GETMESSAGE(9,72,"Copy"));
3488 sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3490 if(cb_data->callback_data == NULL)
3492 if(cb_data->file_mgr_data && cb_data->file_mgr_data->toolbox)
3498 err_msg = GETMESSAGE(11,136,"Cannot copy object %s onto itself");
3502 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");
3507 title = XtCalloc(1,strlen(GETMESSAGE(9,74,"Link"))+
3508 strlen(GETMESSAGE(9,94,"Error"))+5);
3509 tchar = XtNewString(GETMESSAGE(9,74,"Link"));
3510 sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3512 if(cb_data->callback_data == NULL)
3514 err_msg = GETMESSAGE(11,137,"Cannot link object %s onto itself");
3518 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");
3522 msgptr = XtCalloc(1,strlen(err_msg)+strlen(cb_data->updates[index].file)+10);
3523 sprintf(msgptr,err_msg,cb_data->updates[index].file);
3525 if(cb_data->callback_data)
3526 dialogwidget = ((RenameDoneData *)(cb_data->callback_data))->w;
3528 dialogwidget = toplevel;
3529 _DtMessage (dialogwidget,title, msgptr, NULL, HelpRequestCB);
3536 /*==============================================================
3538 * appendErrorMessage
3540 * if "arg" is not null, "new" is assumed to include %s
3541 * "message" is re-allocated and so will have a different
3542 * address than when the function was called
3544 * usage: errorMsg = appendErrorMessage(errorMsg,errStr,file);
3546 *==============================================================
3550 appendErrorMessage(String message, String new, String arg)
3555 newMessage = XtNewString(new);
3558 newMessage = XtMalloc(strlen(new) + strlen(arg) + 1);
3559 sprintf(newMessage,new,arg);
3562 if (message == NULL)
3564 message = XtRealloc(message, (strlen(newMessage) + 2));
3568 message = XtRealloc(message, (strlen(message) + strlen(newMessage) + 2));
3570 strcat(message,newMessage);
3571 strcat(message,"\n");
3577 } /* end appendErrorMessage */
3580 DisplayErrorMessage(
3588 localstr = (char *) XtMalloc(strlen(errMsg)+strlen(from)+strlen(tdir) + 10 );
3589 sprintf(localstr,errMsg,tdir,from);
3590 PipeWriteErrmsg(pipe_s2m, -1, localstr, NULL);
3598 char filename [MAX_PATH];
3600 int slen = strlen(source_path);
3602 if(slen > strlen(dest_path))
3604 strcpy (filename, dest_path);
3605 cptr = strchr(&filename[slen-1],'/');
3608 return ((strcmp(source_path,filename) == 0)?True:False);