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 <X11/ShellP.h>
102 #include <X11/Shell.h>
103 #include <X11/Xutil.h>
104 #include <X11/Xatom.h>
105 #include <X11/keysymdef.h>
108 #include <X11/extensions/shape.h>
112 #include <Dt/IconP.h>
113 #include <Dt/IconFile.h>
114 #include <Dt/Action.h>
115 #include <Dt/Connect.h>
117 #include <Dt/DtNlUtils.h>
118 #include <Dt/HourGlass.h>
123 #include "SharedProcs.h"
131 #include "SharedMsgs.h"
132 #include "sharedFuncs.h"
135 /* Static Function declarations */
137 static Boolean CreateFileFromBuffer(
140 char *fully_qualified_name,
143 static String appendErrorMessage(
147 static void DisplayErrorMessage(
152 static Boolean IsInParentDir(char *from,char *to);
154 /* the amount of time we wait for a file move/copy to complete */
155 /* @@@ should make this a resource */
156 #define FILE_MOVE_COPY_WAIT_TIME 2
159 /* types of messages sent through the pipe */
160 #define PIPEMSG_FILEOP_ERROR 1
161 #define PIPEMSG_EXIST_ERROR 2
162 #define PIPEMSG_OTHER_ERROR 3
163 #define PIPEMSG_CONFIRM 4
164 #define PIPEMSG_TARGET_TIME 5
165 #define PIPEMSG_FILE_MODIFIED 6
166 #define PIPEMSG_DONE 7
167 #define PIPEMSG_REPLACE_RENAME 8
168 #define PIPEMSG_REPLACE_RENAME_SAME 9
169 #define PIPEMSG_REPLACE_MERGE 10
170 #define PIPEMSG_MULTICOLLIDE 11
171 #define PIPEMSG_MULTICOLLIDE_SAME 12
172 #define PIPEMSG_MOVE_TO_SAME_DIR 13
174 /* the following messages are also defined & used in OverWrite.c */
175 #define PIPEMSG_CANCEL 101
176 #define PIPEMSG_PROCEED 102
177 #define PIPEMSG_MERGE 103
178 #define PIPEMSG_REPLACE_BUFFER 104
179 #define PIPEMSG_RENAME_BUFFER 105
180 #define PIPEMSG_MULTI_PROCEED 106
182 extern int G_dropx,G_dropy;
184 /* callback data for file move/copy/link */
189 BufferInfo bufferInfo;
192 Boolean operationStatus;
199 FileMgrData *file_mgr_data;
200 FileMgrRec *file_mgr_rec;
201 FileViewData *file_view_data;
202 DesktopRec *desktopWindow;
203 int pipe_m2s; /* pipe main to slave */
204 int pipe_s2m; /* pipe slave to main */
210 void (*finish_callback)();
211 XtPointer callback_data;
216 /* callback data for file rename */
221 FileViewData *file_view_data;
222 DesktopRec *desktopWindow;
224 char *directory_name;
231 /* callback data for create file/directory */
237 void (*finish_callback)();
238 XtPointer callback_data;
244 DisplayDuplicateOpError(FileOpCBData *cb_data,int index);
248 /*====================================================================
250 * Routine for sending data through a pipe
252 *==================================================================*/
254 /*--------------------------------------------------------------------
256 * Read data from the pipe
257 *------------------------------------------------------------------*/
265 static int whined_fd = -1;
271 rc = read(fd, (char *)buf + n, len - n);
274 else if (rc < 0 && errno == EINTR)
284 "PipeRead: broken pipe, ppid=%d pid=%d fd=%d\n",
285 getppid(), getpid(), fd);
290 perror("dtfile: read failed in PipeRead");
301 /*--------------------------------------------------------------------
303 * write a string to the pipe
304 *------------------------------------------------------------------*/
314 oldPipe = (void (*)())signal(SIGPIPE, SIG_IGN);
321 if (write(fd, &len, sizeof(short)) < 0) {
326 sent = write(fd, s, len);
328 signal(SIGPIPE, oldPipe);
334 /*--------------------------------------------------------------------
336 * read a string from the pipe
337 *------------------------------------------------------------------*/
348 if (PipeRead(fd, &len, sizeof(short)) != sizeof(short))
355 s = (char *)XtMalloc(len + 1);
356 if (PipeRead(fd, s, len) != len)
367 /*--------------------------------------------------------------------
369 * write an error message to the pipe
370 *------------------------------------------------------------------*/
379 short pipe_msg = PIPEMSG_FILEOP_ERROR;
381 DPRINTF(("PipeWriteErrmsg: sending error %d \"%s\"\n", rc, msg));
383 write(fd, &pipe_msg, sizeof(short));
384 write(fd, &rc, sizeof(int));
385 PipeWriteString(fd, msg);
386 PipeWriteString(fd, arg);
392 /*====================================================================
395 * Run a background process to move/copy/link files dropped
396 * on a dtfile window or icon.
398 *==================================================================*/
400 /*--------------------------------------------------------------------
401 * moveCopyLinkCancel:
402 * Cancel-button callback for overwrite confirmation dialog
403 *------------------------------------------------------------------*/
405 int filop_confirm_fd = -1; /* @@@ can't we pass this in client_data? */
410 XtPointer client_data,
411 XtPointer call_data )
413 const int rc = PIPEMSG_CANCEL;
415 /* close the dialog */
416 XtUnmanageChild((Widget)client_data);
417 XmUpdateDisplay((Widget)client_data);
418 XtDestroyWidget((Widget)client_data);
420 /* send return code through the pipe to the background proc */
421 write(filop_confirm_fd, &rc, sizeof(int));
422 filop_confirm_fd = -1;
426 /*--------------------------------------------------------------------
428 * Ok-button callback for overwrite confirmation dialog
429 *------------------------------------------------------------------*/
434 XtPointer client_data,
435 XtPointer call_data )
437 const int rc = PIPEMSG_PROCEED;
439 /* close the dialog */
440 XtUnmanageChild((Widget)client_data);
441 XmUpdateDisplay((Widget)client_data);
442 XtDestroyWidget((Widget)client_data);
444 /* send affirmative return code through the pipe to the background proc */
445 write(filop_confirm_fd, &rc, sizeof(int));
446 filop_confirm_fd = -1;
450 /*--------------------------------------------------------------------
452 * Error handler for FileManip when called in the background process
453 *------------------------------------------------------------------*/
461 int pipe_fd = (int)w; /* @@@ Hack! @@@
462 In the background process we call FileManip with
463 the file descriptor for the pipe instead of a
464 widget id. We rely on the fact that FileManip
465 never uses the widget as a widget, but only
466 passes it to the error handler. */
468 /* write the error message to the pipe */
469 PipeWriteErrmsg(pipe_fd, -1, message1, message2);
473 /*--------------------------------------------------------------------
475 * Send a message through the pipe that informs the main process
476 * that we are about to modify a directory or that a file has been
478 *------------------------------------------------------------------*/
493 struct stat stat_buf;
496 /* if first operation on target dir, send timestamp */
499 if (stat(to, &stat_buf) == 0)
501 modify_time = stat_buf.st_mtime;
502 pipe_msg = PIPEMSG_TARGET_TIME;
503 write(pipe_fd, &pipe_msg, sizeof(short));
504 write(pipe_fd, &modify_time, sizeof(long));
508 /* if first operation on source dir, get timestamp of source dir */
510 j = updates[i].first_index;
511 if (mode == MOVE_FILE && !updates[j].time_sent)
515 dir_path = ResolveLocalPathName(updates[i].host,
516 updates[i].directory,
521 if (stat(dir_path, &stat_buf) == 0)
522 modify_time = stat_buf.st_mtime;
524 updates[j].time_sent = True;
527 /* send the modify message */
528 pipe_msg = PIPEMSG_FILE_MODIFIED;
529 write(pipe_fd, &pipe_msg, sizeof(short));
530 write(pipe_fd, &i, sizeof(int));
531 write(pipe_fd, &modify_time, sizeof(long));
532 PipeWriteString(pipe_fd, target_file);
535 /*--------------------------------------------------------------------
536 * FileMoveCopyProcess:
537 * Main routine of the background process
539 * This routine has two basic modes of operation:
540 * It is given a list of source files and a target directory,
541 * and performs an operation on the source files. This mode
542 * is used for drag & drop operations where a user can
543 * select multiple source files and then drop them on a
544 * target directory to either move, copy, or copy-as-link
545 * the source files to the target directory. The source
546 * and target directories must be different.
547 * It is given a single source file and a target file. The
548 * target can be either a directory or a file. This mode
549 * is used for menu-intiated move, copy, or copy-as-link
550 * operations. The source and target directories can be
552 * The source file(s) are given in updates; the destination is
553 * in host, dirctory, to_file. If to_file is NULL, the
554 * first mode (drag & drop) is assumed, otherwise assume
555 * menu-initiated mode.
557 *------------------------------------------------------------------*/
569 DesktopRec *desktopWindow)
571 char * target_dir, * from, * to;
572 int i, j, rc, result;
573 Boolean return_val = False;
576 char *tmpStr, *target_file;
577 struct stat stat_buf, from_stat_buf;
581 int *sameIndex = NULL, *sameConfirmType = NULL;
582 Boolean first_op = True;
586 String permissionErrors = NULL;
587 Boolean targetChecked = FALSE;
588 Boolean targetError = FALSE;
589 Boolean CopyError=FALSE,MoveError1=FALSE,MoveError2=FALSE;
590 char *CopyString=NULL,*MoveString1=NULL,*MoveString2=NULL;
593 /* Get the fully qualified destination path. */
594 target_dir = (char *)ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
595 if( TT_OK != tt_status )
597 char msg1[2*MAX_PATH];
599 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
600 directory, host, host);
602 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
603 directory, host, host);
605 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
606 pipe_msg = PIPEMSG_FILEOP_ERROR;
608 write(pipe_s2m, &pipe_msg, sizeof(short));
609 write(pipe_s2m, &rc, sizeof(int));
613 DtEliminateDots(target_dir);
615 for (i = 0; i < file_count; i++)
619 /* get full name of the source file, if just */
620 /* dealing with regular files */
621 if (mode != MAKE_BUFFER)
623 from = ResolveLocalPathName(updates[i].host,
624 updates[i].directory,
630 char msg1[2*MAX_PATH];
633 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
634 updates[i].directory, updates[i].host, updates[i].host);
636 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
637 updates[i].directory, updates[i].host, updates[i].host);
639 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
643 /* do some extra error checking if a target filename is specified */
644 /* this is meant for the case of a menu-initiated operation */
647 /* Verify that the target directory already exists */
648 if ( (stat(target_dir, &stat_buf) != 0) ||
649 (! S_ISDIR(stat_buf.st_mode) ) )
654 GETMESSAGE(11,41,"The folder\n%s\ndoes not exist."));
655 PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
663 /* check for a drop of a directory onto itself */
664 if (updates[i].app_man_dir)
666 char *temp_dir = XtNewString(target_dir);
668 temp_dir = _DtResolveAppManPath(temp_dir, updates[i].app_man_dir);
669 if (mode == MOVE_FILE && strcmp(temp_dir, from) == 0)
674 GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
675 PipeWriteErrmsg( pipe_s2m, -1, msg, temp_dir );
684 else if (mode == MOVE_FILE && strcmp(target_dir, from) == 0)
689 GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
690 PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
696 else if (mode == MOVE_FILE && stat(from, &stat_buf) == 0 &&
697 S_ISDIR(stat_buf.st_mode) && DirectoryBusy(from))
701 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."));
703 PipeWriteErrmsg( pipe_s2m, -1, msg, from );
711 /* for copy operations, check for read permission on the source file */
712 /* the error message is appended to a list and dealt with later */
713 /* the current file is not processed */
714 if (mode == COPY_FILE)
715 if (CheckAccess(from,R_OK) == -1)
720 /* 'errno' is not giving correct results like 'ENOENT' in order to
721 use it here, may be because of the other system calls in
724 if (stat(from, &sbuf) < 0)
725 tmpStr = (GETMESSAGE(28,13,"Object:\n\n %s\n\n does not exist in the file system"));
727 tmpStr = GetSharedMessage(CANT_READ_ERROR);
729 permissionErrors = appendErrorMessage(permissionErrors, tmpStr, from);
736 if (strcmp(target_dir, "/") == 0)
738 target_file = (char *)XtMalloc(strlen(target_dir) +
739 strlen(updates[i].file) + 1);
740 sprintf(target_file, "%s%s", target_dir, updates[i].file);
744 target_file = (char *)XtMalloc(strlen(target_dir) +
745 strlen(updates[i].file) + 2);
746 sprintf(target_file, "%s/%s", target_dir, updates[i].file);
751 if (strcmp(target_dir, "/") == 0)
753 target_file = (char *)XtMalloc(strlen(target_dir) +
754 strlen(to_file) + 1);
755 sprintf(target_file, "%s%s", target_dir, to_file);
759 target_file = (char *)XtMalloc(strlen(target_dir) +
760 strlen(to_file) + 2);
761 sprintf(target_file, "%s/%s", target_dir, to_file);
764 if (updates[i].app_man_dir)
765 target_file = _DtResolveAppManPath(target_file,
766 updates[i].app_man_dir);
767 /* check if source and target files are the same.
768 * if they are the same, set a flag noting that they are. If the
769 * the operation is a move, it doesn't make any sense to move it, so
770 * send back a MOVE_TO_SAME_DIR msg.
773 if ((mode != MAKE_BUFFER) && (strcmp(target_file, from) == 0))
775 if (mode == MOVE_FILE && stat(target_file, &stat_buf) == 0)
777 if(S_ISDIR(stat_buf.st_mode))
779 pipe_msg = PIPEMSG_MOVE_TO_SAME_DIR;
780 write(pipe_s2m, &pipe_msg, sizeof(short));
781 write(pipe_s2m, &i, sizeof(int));
790 /* for copy operations, check for write permission on the target */
792 /* for move operations, check for write permission on the source and */
793 /* target directories */
794 /* the error message is appended to a list and dealt with later */
795 /* the current file is not processed */
796 if (mode == COPY_FILE)
798 if (CheckAccess(target_dir,W_OK) == -1)
802 if(CopyString == NULL)
803 CopyString = XtNewString(from);
806 CopyString = (char *) XtRealloc(CopyString,strlen(CopyString)+
808 strcat(CopyString,"\n");
809 strcat(CopyString,from);
814 else if (mode == MOVE_FILE)
816 Boolean error = FALSE;
817 if (targetChecked || CheckAccess(target_dir,W_OK) == -1)
820 if(MoveString1 == NULL)
821 MoveString1 = XtNewString(from);
824 MoveString1=(char *)XtRealloc(MoveString1,strlen(MoveString1)+
826 strcat(MoveString1,"\n");
827 strcat(MoveString1,from);
829 error = targetError = TRUE;
830 targetChecked = TRUE;
832 if (CheckAccess(_DtPName(from),W_OK) == -1)
835 if(MoveString2 == NULL)
836 MoveString2 = XtNewString(from);
839 MoveString2 = (char *)XtRealloc(MoveString2,strlen(MoveString2)+
841 strcat(MoveString2,"\n");
842 strcat(MoveString2,from);
846 if (error || targetError)
853 /* check if target file already exists */
854 if (stat(target_file, &stat_buf) == 0)
856 /* target file already exists: remember and deal with it later */
857 if(mode == MOVE_FILE && S_ISDIR(stat_buf.st_mode)
858 && DirectoryBusy(target_file))
862 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."));
864 PipeWriteErrmsg( pipe_s2m, -1, msg, target_file );
870 if (sameIndex == NULL)
872 sameIndex = (int *)XtMalloc(file_count*sizeof(int));
873 sameConfirmType = (int *)XtMalloc(file_count*sizeof(int));
875 sameIndex[sameCount] = i;
877 /* determine how to set the pipe message */
878 if (mode == MAKE_BUFFER)
880 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
884 stat(from, &from_stat_buf);
885 if ( S_ISDIR(from_stat_buf.st_mode) &&
886 S_ISDIR(stat_buf.st_mode) &&
889 /* if its a directory and there already is a directory of the
890 * same name the user may want to merge the directories into
891 * one directory. But if the directory to be copied is being
892 * copied into the same directory it came from, it doesn't make
893 * sense to merge. Set up message to REPLACE_RENAME_SAME
894 * indicating it is being copied from and to the same directory
897 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
899 sameConfirmType[sameCount] = PIPEMSG_REPLACE_MERGE;
903 /* If the copy/move/link is to the same directory, set up a
904 * different case then when the op is happening from different
908 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
910 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
912 } /* endif mode != MAKE_BUFFER */
916 if (mode != MAKE_BUFFER)
917 XtFree ((char *) from);
919 XtFree ((char *) target_file);
921 } /* endif targetfile already exists */
923 if ((isContainer = (to_file == NULL)))
929 * Note: it is important that SendModifyMsg is called before any
930 * changes are made to either the source or target directory.
931 * This is because SendModifyMsg is supposed to obtain and send
932 * the time stamp of the directories BEFORE any operation. If
933 * the wrong timestamp is sent, the window will be updated and
934 * redrawn twice instead of just once.
936 SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, i,
940 if (mode == MAKE_BUFFER)
942 /* Call CreateFileFromBuffer */
943 return_val = CreateFileFromBuffer(pipe_s2m, to,
945 updates[i].bufferInfo.buf_ptr,
946 updates[i].bufferInfo.size);
950 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
951 return_val = FileManip((Widget)pipe_s2m, mode, from, to,
953 FileOpError, True, DESKTOP);
955 return_val = FileManip((Widget)pipe_s2m, mode, from, to,
957 FileOpError, True, NOT_DESKTOP);
958 XtFree( (char *) from );
961 XtFree ((char *) target_file);
965 if(CopyError == TRUE)
968 errMsg = GETMESSAGE(11,48,
969 "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");
970 DisplayErrorMessage(pipe_s2m,errMsg,CopyString,target_dir);
972 permissionErrors = NULL;
976 if(MoveError1 == TRUE)
979 errMsg = GETMESSAGE(11,49,
980 "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");
981 DisplayErrorMessage(pipe_s2m,errMsg,MoveString1,target_dir);
983 permissionErrors = NULL;
987 if(MoveError2 == TRUE)
990 errMsg = GETMESSAGE(11,50,
991 "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");
992 DisplayErrorMessage(pipe_s2m,errMsg,MoveString2,target_dir);
994 permissionErrors = NULL;
1000 /* If there were any permissions errors, show the error message */
1001 if (permissionErrors != NULL)
1003 PipeWriteErrmsg(pipe_s2m, -1, permissionErrors, NULL);
1004 XtFree(permissionErrors);
1009 * Now deal with with the cases where we found that the target file
1016 * @@@ Note: The code below for sending a target-time pipe message
1017 * at this point shouldn't really be necessary.
1018 * The problem is that the target directory time stamp MUST be
1019 * obtained BEFORE any changes are made to the directory;
1020 * otherwise, the window will be updated and redrawn twice instead
1021 * of just once. Unfortunately, currently, if the user chooses to
1022 * replace or rename the existing file, the rename or delete
1023 * operation is done in the main process (inside the
1024 * replace_rename_ok_callback in Overwrite.c), instead of here in
1025 * the child process where it belongs (the main process shouldn't
1026 * do any file system operations because they could block for a
1027 * long time on a slow server). If and when overwrite dialog code
1028 * is fixed, the code below can be deleted; the target-time
1029 * message will then be sent by the call to SendModifyMsg further
1030 * below after the call to PipeRead.
1034 if (stat(target_dir, &stat_buf) == 0)
1036 modify_time = stat_buf.st_mtime;
1037 pipe_msg = PIPEMSG_TARGET_TIME;
1038 write(pipe_s2m, &pipe_msg, sizeof(short));
1039 write(pipe_s2m, &modify_time, sizeof(long));
1044 /* send message to main process to display dialog (and possibly remove/rename files) */
1045 if (file_count == 1)
1047 if (to_file == NULL) /* note target_file here is only file name, above it is full path */
1048 target_file = updates[sameIndex[0]].file;
1050 target_file = to_file;
1051 pipe_msg = sameConfirmType[0];
1052 DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
1053 write(pipe_s2m, &pipe_msg, sizeof(short));
1054 DPRINTF(("FileMoveCopyProcess: sending: mode %d directory \"%s\" file \"%s\" \n",
1055 mode, directory, target_file));
1056 write(pipe_s2m, &mode, sizeof(int));
1057 PipeWriteString(pipe_s2m, directory);
1058 PipeWriteString(pipe_s2m, target_file);
1062 int processCount=file_count-errorCount;
1064 /* If the copy/move/link is to the same directory, set up a
1065 * different case then when the op is happening from different
1069 pipe_msg = PIPEMSG_MULTICOLLIDE_SAME;
1071 pipe_msg = PIPEMSG_MULTICOLLIDE;
1073 DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
1074 write(pipe_s2m, &pipe_msg, sizeof(short));
1075 DPRINTF(("FileMoveCopyProcess: sending: mode %d processCount %d sameCount %d directory \"%s\"\n",
1076 mode, processCount, sameCount, directory));
1077 write(pipe_s2m, &mode, sizeof(int));
1078 write(pipe_s2m, &processCount, sizeof(int));
1079 write(pipe_s2m, &sameCount, sizeof(int));
1080 PipeWriteString(pipe_s2m, directory);
1081 DPRINTF(("FileMoveCopyProcess: sending %d filename strings\n", sameCount));
1082 for (i = 0; i < sameCount; i++)
1083 PipeWriteString(pipe_s2m, updates[sameIndex[i]].file);
1086 /* wait for reply from main process */
1088 PipeRead(pipe_m2s, &rc, sizeof(int));
1089 DPRINTF(("FileMoveCopyProcess: woke up after confirm, rc %d\n", rc));
1090 if (rc != PIPEMSG_CANCEL)
1092 /* affirmative reply: do the operation */
1093 for(i = 0; i < sameCount; i++)
1096 if (rc != PIPEMSG_RENAME_BUFFER)
1098 SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, j,
1102 if (rc == PIPEMSG_MULTI_PROCEED)
1105 PipeRead(pipe_m2s, &opvalue, sizeof(int));
1110 if (mode != MAKE_BUFFER)
1112 from = ResolveLocalPathName( updates[j].host,
1113 updates[j].directory,
1117 if( TT_OK != tt_status )
1119 char msg1[2*MAX_PATH];
1122 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1123 updates[j].directory, updates[j].host,
1126 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1127 updates[j].directory, updates[j].host,
1130 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
1137 if ( (isContainer = (to_file == NULL)) )
1143 to = (char *)XtMalloc(strlen(target_dir) + strlen(to_file) + 2);
1144 sprintf(to, "%s/%s", target_dir, to_file);
1149 /* check the return code for type of message and */
1150 /* perform the appropriate action */
1155 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
1156 return_val = FileManip((Widget)pipe_s2m, MERGE_DIR, from,
1158 FileOpError, True, DESKTOP);
1160 return_val = FileManip((Widget)pipe_s2m, MERGE_DIR, from,
1162 FileOpError, True, NOT_DESKTOP);
1165 case PIPEMSG_REPLACE_BUFFER:
1166 target_file = (char *)XtMalloc(strlen(to) + strlen(updates[j].file)
1168 sprintf(target_file, "%s/%s", to, updates[j].file);
1169 DPRINTF (("file is %s",updates[j].file));
1170 return_val = CreateFileFromBuffer(pipe_s2m,
1173 updates[j].bufferInfo.buf_ptr,
1174 updates[j].bufferInfo.size);
1175 XtFree((char *)target_file);
1178 case PIPEMSG_RENAME_BUFFER:
1180 renamed_file = PipeReadString(pipe_m2s);
1182 SendModifyMsg(pipe_s2m, mode, first_op, to, updates, j, renamed_file);
1183 target_file = (char *)XtMalloc(strlen(to) + strlen(renamed_file)
1185 sprintf(target_file, "%s/%s", to, renamed_file);
1186 DPRINTF(("file is %s",renamed_file));
1187 return_val = CreateFileFromBuffer(pipe_s2m,
1190 updates[j].bufferInfo.buf_ptr,
1191 updates[j].bufferInfo.size);
1192 XtFree((char *) target_file);
1197 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
1198 return_val = FileManip((Widget)pipe_s2m, mode, from, to,
1199 isContainer,FileOpError, True,
1203 /* if the operation (move/copy/link) is happening from
1204 * and to the same folder, we want to create a new name
1205 * for the object for which the operation is happening
1210 char path[MAX_PATH], newDir[MAX_PATH],
1215 generate_NewPath(path,path);
1216 split_path(path, newDir, newFile);
1217 toFile = (char *)XtMalloc(strlen(newDir) +
1218 strlen(newFile) + 3);
1219 strcpy(toFile, newDir);
1220 strcat(toFile, "/");
1221 strcat(toFile, newFile);
1223 return_val = FileManip((Widget)pipe_s2m, mode, from,
1224 toFile, False, FileOpError,
1230 return_val = FileManip((Widget)pipe_s2m, mode, from,
1231 to, isContainer, FileOpError,
1236 if (to_file != NULL)
1238 XtFree ((char *) to);
1242 }/*end if rc != PIPEMSG_CANCEL*/
1245 XtFree((char *)sameIndex);
1247 XtFree((char *)sameConfirmType);
1248 sameConfirmType = NULL;
1250 } /* endif sameCount != 0 */
1253 pipe_msg = PIPEMSG_DONE;
1254 if (rc != PIPEMSG_CANCEL)
1255 rc = return_val? 0: -1;
1258 write(pipe_s2m, &pipe_msg, sizeof(short));
1259 write(pipe_s2m, &rc, sizeof(int));
1261 XtFree ((char *) target_dir);
1268 /*--------------------------------------------------------------------
1269 * FileMoveCopyProcessDesktop:
1270 * Main routine of the background process that handles files
1271 * dropped in desktop icons.
1272 *------------------------------------------------------------------*/
1275 FileMoveCopyProcessDesktop(
1283 DesktopRec *desktopWindow)
1287 Boolean first_op = True;
1288 Boolean return_val = False;
1290 Tt_status tt_status;
1292 /* Get the fully qualified destination path. */
1293 to = ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
1294 if( TT_OK != tt_status )
1296 char msg1[2*MAX_PATH];
1298 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1299 directory, host, host);
1301 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1302 directory, host, host);
1304 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
1305 pipe_msg = PIPEMSG_FILEOP_ERROR;
1307 write(pipe_s2m, &pipe_msg, sizeof(short));
1308 write(pipe_s2m, &rc, sizeof(int));
1311 DtEliminateDots(to);
1313 for (i = 0; i < file_count; i++)
1315 /* get full name of the source file, if just */
1316 /* dealing with regular files */
1317 if (mode != MAKE_BUFFER)
1319 from = ResolveLocalPathName(updates[i].host,
1320 updates[i].directory,
1326 char msg[2*MAX_PATH];
1329 sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1330 updates[i].directory, updates[i].host, updates[i].host);
1332 sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1333 updates[i].directory, updates[i].host, updates[i].host);
1335 PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
1337 else if (strcmp(to, from) == 0)
1339 char msg[2*MAX_PATH];
1341 sprintf(msg,GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"),to);
1342 PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
1343 XtFree ((char *) from);
1346 } /* end if dealing with regular files */
1349 SendModifyMsg(pipe_s2m, mode, first_op, to, updates, i, updates[i].file);
1353 if (mode == MAKE_BUFFER)
1357 if (strcmp(to, "/") == 0)
1359 target_file = (char *) XtMalloc(strlen(to) +
1360 strlen(updates[i].file) + 1);
1361 sprintf(target_file, "%s%s", to, updates[i].file);
1365 target_file = (char *) XtMalloc(strlen(to) +
1366 strlen(updates[i].file) + 2);
1367 sprintf(target_file, "%s/%s", to, updates[i].file);
1370 return_val = CreateFileFromBuffer(pipe_s2m,
1373 updates[i].bufferInfo.buf_ptr,
1374 updates[i].bufferInfo.size);
1378 return_val = FileManip((Widget)pipe_s2m, mode, from, to, TRUE,
1379 FileOpError, True, DESKTOP);
1385 pipe_msg = PIPEMSG_DONE;
1386 rc = return_val? 0: -1;
1387 write(pipe_s2m, &pipe_msg, sizeof(short));
1388 write(pipe_s2m, &rc, sizeof(int));
1390 XtFree ((char *) to);
1396 RemoveIconFromWorkspace( char * iconName,
1399 DesktopRec *desktopWin;
1401 char fileName[MAX_PATH];
1404 for(i = 0; i < desktop_data->numIconsUsed; i++)
1406 desktopWin = desktop_data->desktopWindows[i];
1408 if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
1409 sprintf( fileName, "/%s", desktopWin->file_name );
1411 sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
1413 if( strcmp( fileName, iconName ) == 0 )
1417 Screen *currentScreen;
1419 char *workspace_name;
1421 screen = XDefaultScreen(XtDisplay(desktopWin->shell));
1423 XScreenOfDisplay(XtDisplay(desktopWin->shell), screen);
1424 rootWindow = RootWindowOfScreen(currentScreen);
1426 if(DtWsmGetCurrentWorkspace(XtDisplay(desktopWin->shell),
1427 rootWindow, &pCurrent) == Success)
1429 XGetAtomName (XtDisplay(desktopWin->shell), pCurrent);
1431 workspace_name = XtNewString("One");
1433 if( strcmp( workspace_name, desktopWin->workspace_name ) == 0 )
1435 RemoveDT( desktopWin->shell, (XtPointer) desktopWin,
1440 XtFree( desktopWin->dir_linked_to );
1441 desktopWin->dir_linked_to = XtNewString( targetDir );
1444 XtFree(workspace_name);
1450 ChangeWorkspaceIconLink( FileMgrData *fmd,
1455 DesktopRec *desktopWin;
1458 char fileName[MAX_PATH];
1461 for(i = 0; i < desktop_data->numIconsUsed; i++)
1463 desktopWin = desktop_data->desktopWindows[i];
1465 if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
1466 sprintf( fileName, "/%s", desktopWin->file_name );
1468 sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
1470 DtEliminateDots(fileName);
1471 if( strcmp( fileName, iconName ) == 0 )
1472 dirp = XtNewString(targetDir);
1473 else if(IsInParentDir(iconName,desktopWin->dir_linked_to))
1475 int index = strlen(iconPdir);
1476 char *tptr = desktopWin->dir_linked_to;
1478 dirp = XtCalloc( 1, strlen(targetDir)+ strlen(&tptr[index])+1);
1479 sprintf(dirp,"%s%s",targetDir,&tptr[index]);
1484 FileViewData *file_view_data;
1485 DirectorySet *directory_set;
1486 FileMgrData *file_mgr_data;
1487 Tt_status tt_status;
1488 char * full_dir_name;
1490 file_view_data = desktopWin->file_view_data;
1491 directory_set = (DirectorySet *)file_view_data->directory_set;
1492 file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
1495 fmd = file_mgr_data;
1496 FreeFileData( file_view_data->file_data, True );
1497 file_view_data->file_data = NULL;
1499 XtFree( desktopWin->dir_linked_to );
1500 desktopWin->dir_linked_to = XtNewString( dirp );
1501 DtEliminateDots(desktopWin->dir_linked_to);
1505 if (fmd->restricted_directory == NULL)
1506 desktopWin->restricted_directory = NULL;
1508 desktopWin->restricted_directory =
1509 XtNewString(fmd->restricted_directory);
1511 if (fmd->helpVol == NULL)
1512 desktopWin->helpVol = NULL;
1514 desktopWin->helpVol = XtNewString(fmd->helpVol);
1516 desktopWin->helpVol = XtNewString( fmd->helpVol );
1517 desktopWin->view = fmd->view;
1518 desktopWin->order = fmd->order;
1519 desktopWin->direction = fmd->direction;
1520 desktopWin->positionEnabled = fmd->positionEnabled;
1521 desktopWin->toolbox = fmd->toolbox;
1524 full_dir_name = ResolveLocalPathName(desktopWin->host,
1529 if( TT_OK == tt_status )
1531 FileData2 file_data2;
1535 DtEliminateDots (full_dir_name);
1538 IsToolBox = fmd->toolbox;
1542 if (strcmp(desktopWin->file_name, ".") == 0)
1543 ReadFileData2(&file_data2, full_dir_name, NULL, IsToolBox);
1545 ReadFileData2(&file_data2, full_dir_name, desktopWin->file_name,
1548 file_view_data->file_data = FileData2toFileData(&file_data2, &n);
1549 XtFree(full_dir_name);
1550 full_dir_name = NULL;
1553 ((DirectorySet *)file_view_data->directory_set)->name =
1556 SaveDesktopInfo(NORMAL_RESTORE);
1563 /*--------------------------------------------------------------------
1565 * Read and process data sent through the pipe.
1566 *------------------------------------------------------------------*/
1570 XtPointer client_data,
1574 FileOpCBData *cb_data = (FileOpCBData *)client_data;
1577 char *title, *err_msg, *err_arg;
1578 char *directory, *file, *target_file;
1582 int nSelected, nCollisions;
1584 static int status = 0;
1586 static ActionAreaItem replace_rename_actionItems[] = {
1587 {"Ok", 9, 27, NULL, NULL}, /* changed later based on mode */
1588 {"Cancel", 9, 28, replace_rename_cancel_callback, NULL},
1589 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_REN},
1592 ActionAreaDefn replace_renameActions = {
1593 XtNumber(replace_rename_actionItems),
1594 1, /* Cancel is default action */
1595 replace_rename_actionItems
1598 static ActionAreaItem replace_merge_actionItems[] = {
1599 {"Ok", 9, 27, replace_merge_ok_callback, NULL},
1600 {"Cancel", 9, 28, replace_merge_cancel_callback, NULL}, /* changed below depending on mode */
1601 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_MRG},
1604 ActionAreaDefn replace_mergeActions = {
1605 XtNumber(replace_merge_actionItems),
1606 1, /* Cancel is default action */
1607 replace_merge_actionItems
1610 static ActionAreaItem multicollide_actionItems[] = {
1611 {"Ok", 9, 27, NULL, NULL}, /* changed later based on Mode */
1612 {"Cancel", 9, 28, multicollide_cancel_callback, NULL}, /* changed below depending on mode */
1613 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_MULTI},
1616 ActionAreaDefn multicollideActions = {
1617 XtNumber(multicollide_actionItems),
1618 1, /* Cancel is default action */
1619 multicollide_actionItems
1623 /* Initialize Action Area structures based on mode */
1624 /* Set the appropriate callback routines */
1625 mode = cb_data->mode;
1629 replace_rename_actionItems[0].callback =
1630 buffer_replace_rename_ok_callback;
1631 multicollide_actionItems[0].callback =
1632 buffer_multicollide_ok_callback;
1635 replace_rename_actionItems[0].callback =
1636 replace_rename_ok_callback;
1637 multicollide_actionItems[0].callback =
1638 multicollide_ok_callback;
1643 /* read the next msg from the pipe */
1645 n = PipeRead(*fd, &pipe_msg, sizeof(short));
1646 DPRINTF(("FileOpPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
1651 case PIPEMSG_FILEOP_ERROR:
1652 PipeRead(*fd, &rc, sizeof(int));
1653 err_msg = PipeReadString(*fd);
1654 err_arg = PipeReadString(*fd);
1655 if (cb_data->desktop)
1656 FileOperationError(cb_data->file_view_data->widget,
1660 /* routine can be called with a NULL file_mgr_rec, use the
1661 * top level widget if this is the case.
1663 if(cb_data->file_mgr_rec)
1664 FileOperationError(cb_data->file_mgr_rec->file_window,
1667 FileOperationError(toplevel, err_msg, err_arg);
1671 if(cb_data->callback_data)
1673 RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
1674 ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
1675 ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
1677 status = PIPEMSG_FILEOP_ERROR;
1680 case PIPEMSG_CONFIRM:
1681 err_msg = PipeReadString(*fd);
1682 title = XtNewString(GETMESSAGE(9,11, "File Manager - Move/Copy/Link Warning"));
1683 filop_confirm_fd = cb_data->pipe_m2s;
1684 _DtMessageDialog(toplevel, title, err_msg, NULL, TRUE,
1685 moveCopyLinkCancel, moveCopyLinkOK, NULL,
1686 HelpRequestCB, False, QUESTION_DIALOG);
1691 case PIPEMSG_REPLACE_RENAME_SAME:
1692 /* filename collision: display replace/rename dialog */
1693 PipeRead(*fd, &mode, sizeof(int));
1694 directory = PipeReadString(*fd);
1695 file = PipeReadString(*fd);
1696 /* routine can be called with a NULL file_mgr_rec, use the
1697 * top level widget if this is the case.
1700 /* the object is copying/linking itself to the same folder. Want
1701 * to indicate the to the ok dialog and the building of the replace
1704 replace_rename_actionItems[0].data = (XtPointer)True;
1705 if(cb_data->file_mgr_rec)
1706 create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
1707 mode, directory, file,
1709 replace_renameActions, True);
1711 create_replace_rename_dialog(toplevel,
1712 mode, directory, file,
1714 replace_renameActions, True);
1719 case PIPEMSG_REPLACE_RENAME:
1720 /* filename collision: display replace/rename dialog */
1721 PipeRead(*fd, &mode, sizeof(int));
1722 directory = PipeReadString(*fd);
1723 file = PipeReadString(*fd);
1724 /* routine can be called with a NULL file_mgr_rec, use the
1725 * top level widget if this is the case.
1727 replace_rename_actionItems[0].data = (XtPointer)NULL;
1728 if(cb_data->file_mgr_rec)
1729 create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
1730 mode, directory, file,
1732 replace_renameActions, False);
1734 create_replace_rename_dialog(toplevel,
1735 mode, directory, file,
1737 replace_renameActions, False);
1742 case PIPEMSG_REPLACE_MERGE:
1743 /* filename collision: display replace/merge dialog */
1744 PipeRead(*fd, &mode, sizeof(int));
1745 directory = PipeReadString(*fd);
1746 file = PipeReadString(*fd);
1747 /* routine can be called with a NULL file_mgr_rec, use the
1748 * top level widget if this is the case.
1750 if(cb_data->file_mgr_rec)
1751 create_replace_merge_dialog(cb_data->file_mgr_rec->shell,
1752 mode, directory, file,
1754 replace_mergeActions);
1756 create_replace_merge_dialog(toplevel,
1757 mode, directory, file,
1759 replace_mergeActions);
1764 case PIPEMSG_MULTICOLLIDE_SAME:
1765 /* filename collision: display multicollide dialog */
1766 PipeRead(*fd, &mode, sizeof(int));
1767 PipeRead(*fd, &nSelected, sizeof(int));
1768 PipeRead(*fd, &nCollisions, sizeof(int));
1769 directory = PipeReadString(*fd);
1770 file = XtMalloc( MAX_PATH );
1771 fileList = (String *) XtMalloc(nCollisions * sizeof(String)); /* de- allocated in dialog's callback functions */
1772 for (i = 0; i < nCollisions; i++)
1774 fileList[i] = PipeReadString(*fd);
1776 /* routine can be called with a NULL file_mgr_rec, use the
1777 * top level widget if this is the case.
1780 /* the object is copying/linking itself to the same folder. Want
1781 * to indicate the to the ok dialog and the building of the replace
1784 multicollide_actionItems[0].data = (XtPointer)True;
1785 if(cb_data->file_mgr_rec)
1786 create_multicollide_dialog(cb_data->file_mgr_rec->shell,
1787 mode, nSelected, nCollisions,
1788 directory, fileList,
1790 multicollideActions, True);
1792 create_multicollide_dialog(toplevel,
1793 mode, nSelected, nCollisions,
1794 directory, fileList,
1796 multicollideActions, True);
1800 case PIPEMSG_MULTICOLLIDE:
1801 /* filename collision: display multicollide dialog */
1802 PipeRead(*fd, &mode, sizeof(int));
1803 PipeRead(*fd, &nSelected, sizeof(int));
1804 PipeRead(*fd, &nCollisions, sizeof(int));
1805 directory = PipeReadString(*fd);
1806 file = XtMalloc( MAX_PATH );
1807 fileList = (String *) XtMalloc(nCollisions * sizeof(String)); /* de-allocated in dialog's callback functions */
1808 for (i = 0; i < nCollisions; i++)
1810 fileList[i] = PipeReadString(*fd);
1812 /* routine can be called with a NULL file_mgr_rec, use the
1813 * top level widget if this is the case.
1815 multicollide_actionItems[0].data = (XtPointer)NULL;
1816 if(cb_data->file_mgr_rec)
1817 create_multicollide_dialog(cb_data->file_mgr_rec->shell,
1818 mode, nSelected, nCollisions,
1819 directory, fileList,
1821 multicollideActions, False);
1823 create_multicollide_dialog(toplevel,
1824 mode, nSelected, nCollisions,
1825 directory, fileList,
1827 multicollideActions, False);
1832 case PIPEMSG_TARGET_TIME:
1833 /* get the modify time and update the directory cache */
1834 PipeRead(*fd, &modify_time, sizeof(long));
1835 DirectoryModifyTime(cb_data->host, cb_data->directory, modify_time);
1838 case PIPEMSG_MOVE_TO_SAME_DIR:
1839 /* get the update index */
1840 PipeRead(*fd, &i, sizeof(int));
1841 cb_data->updates[i].operationStatus = True;
1842 DisplayDuplicateOpError((void *) cb_data,i);
1843 status = PIPEMSG_MOVE_TO_SAME_DIR;
1844 if(cb_data->callback_data)
1846 RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
1847 ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
1848 ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
1852 case PIPEMSG_FILE_MODIFIED:
1853 /* get the update index and modify time */
1854 PipeRead(*fd, &i, sizeof(int));
1855 PipeRead(*fd, &modify_time, sizeof(long));
1856 target_file = PipeReadString(*fd);
1857 DPRINTF (("PIPEMSG_FILE_MODIFIED %s\n", target_file));
1859 /* mark the file updated in the cached target directory */
1860 DirectoryFileModified(cb_data->host, cb_data->directory,
1863 if (cb_data->mode == MOVE_FILE)
1865 /* mark the file updated in the cached source directory */
1866 if (modify_time != 0)
1867 DirectoryModifyTime(cb_data->updates[i].host,
1868 cb_data->updates[i].directory,
1870 DirectoryFileModified(cb_data->updates[i].host,
1871 cb_data->updates[i].directory,
1872 cb_data->updates[i].file);
1874 cb_data->updates[i].operationStatus = True;
1875 XtFree(target_file); target_file = NULL;
1879 PipeRead(*fd, &rc, sizeof(int));
1884 fprintf(stderr, "Internal error in FileOpPipeCB: bad pipe_msg %d\n",
1892 char tmpDir[MAX_PATH];
1894 DPRINTF(("FileOpPipeCB: done, rc %d\n", rc));
1896 /* close the pipe and cancel the callback */
1897 close(cb_data->pipe_m2s);
1898 close(cb_data->pipe_s2m);
1902 *fd = (rc == 0)? 0: -1;
1904 /* arrange for modified directories to be updated */
1905 DirectoryEndModify(cb_data->host, cb_data->directory);
1907 /* Reposition the objects which have been modified */
1908 if(!cb_data->finish_callback && cb_data->file_mgr_data)
1912 /* Do this only if it is the current directory and Random placement
1914 if(cb_data->file_mgr_data->positionEnabled != RANDOM_OFF && strcmp(
1915 cb_data->directory,cb_data->file_mgr_data->current_directory)==0)
1917 file_set = (char **) XtCalloc(1,cb_data->file_count*sizeof(char *));
1918 for(i=0;i<cb_data->file_count;i++)
1920 if(cb_data->updates[i].operationStatus == True)
1921 file_set[actual_count++] = cb_data->updates[i].file;
1923 RepositionIcons(cb_data->file_mgr_data, file_set,actual_count,
1924 G_dropx, G_dropy, True);
1925 XtFree((char *)file_set);
1930 for(i = 0; i < desktop_data->numWorkspaces; i++)
1931 DeselectAllDTFiles(desktop_data->workspaceData[i]);
1933 for (i = 0; i < cb_data->file_count; i++)
1935 char fileName[MAX_PATH];
1937 /* Scroll the window to show the created object, since we
1938 cannot keep scrolling for each object we just do it for
1939 one object and we do it in case of Drag/Drop, but not
1940 for Select.MoveTo/CopyTo ... */
1942 if(!i && cb_data->callback_data == NULL)
1946 if(cb_data && cb_data->file_mgr_data)
1948 fmd = cb_data->file_mgr_data;
1949 fmd->scrollToThisDirectory = XtNewString(cb_data->directory);
1950 fmd->scrollToThisFile = XtNewString(cb_data->updates[i].file);
1953 if (cb_data->updates[i].first_index == i)
1955 if (cb_data->mode == MOVE_FILE)
1957 DirectoryEndModify(cb_data->updates[i].host,
1958 cb_data->updates[i].directory);
1959 if( strcmp( cb_data->updates[i].directory, "/" ) == 0 )
1962 sprintf( tmpDir, cb_data->updates[i].directory );
1965 if( cb_data->updates[i].host )
1966 XtFree( cb_data->updates[i].host );
1967 if( cb_data->updates[i].directory )
1968 XtFree( cb_data->updates[i].directory );
1969 if( cb_data->updates[i].app_man_dir )
1970 XtFree( cb_data->updates[i].app_man_dir );
1973 if( cb_data->mode == MOVE_FILE )
1975 sprintf( fileName, "%s/%s", tmpDir, cb_data->updates[i].file );
1976 if( cb_data->updates[i].operationStatus == True )
1978 if( status == PIPEMSG_MOVE_TO_SAME_DIR )
1980 RemoveIconFromWorkspace( fileName, cb_data->directory );
1982 else if( status != PIPEMSG_FILEOP_ERROR )
1984 ChangeWorkspaceIconLink(cb_data->file_mgr_data, fileName,
1985 cb_data->directory,tmpDir );
1987 /* If it is workspace drag and drop and the move operation
1988 is not because of Select.MoveTo menu option */
1990 if(initiating_view == NULL && cb_data->callback_data == NULL)
1992 sprintf( fileName, "%s/%s", cb_data->directory,
1993 cb_data->updates[i].file );
1994 DtEliminateDots(fileName);
1995 RemoveIconFromWorkspace( fileName, cb_data->directory );
2001 XtFree(cb_data->updates[i].file);
2006 /* call the callback routine */
2007 if (cb_data->finish_callback)
2008 (*cb_data->finish_callback)(cb_data->callback_data, rc);
2010 /* free the callback data */
2011 XtFree((char *)cb_data->updates);
2012 XtFree((char *)cb_data->directory);
2013 XtFree((char *)cb_data->host);
2014 XtFree(client_data);
2019 /*--------------------------------------------------------------------
2021 * Start the background process and set up callback for the pipe.
2022 *------------------------------------------------------------------*/
2032 BufferInfo *buffer_set,
2034 unsigned int modifiers,
2035 DesktopRec *desktopWindow,
2036 void (*finish_callback)(),
2037 XtPointer callback_data)
2039 static char *pname = "_FileMoveCopy";
2041 FileOpCBData *cb_data;
2045 char *source_dir = NULL;
2046 char *source_file = NULL;
2052 struct timeval now, select_end, select_timeout;
2053 Boolean operation_done;
2057 /* Determine the type of operation: move, copy, or link */
2058 /* or creating buffers */
2059 if (buffer_set != NULL)
2065 modifiers &= ~Button2Mask;
2066 if (modifiers == ShiftMask)
2068 else if (modifiers == ControlMask)
2074 /* set up the callback data structure */
2075 cb_data = XtNew(FileOpCBData);
2076 cb_data->desktop = (desktopWindow != NULL);
2077 if (cb_data->desktop)
2079 cb_data->file_mgr_data = NULL;
2080 cb_data->file_mgr_rec = NULL;
2081 cb_data->file_view_data = (FileViewData *)data;
2082 cb_data->desktopWindow = desktopWindow;
2088 cb_data->file_mgr_data = (FileMgrData *)data;
2089 cb_data->file_mgr_rec =
2090 (FileMgrRec *) ((FileMgrData *)data)->file_mgr_rec;
2094 cb_data->file_mgr_data = NULL;
2095 cb_data->file_mgr_rec = NULL;
2097 cb_data->file_view_data = NULL;
2098 cb_data->desktopWindow = NULL;
2100 cb_data->mode = mode;
2101 cb_data->host = XtNewString(host);
2102 cb_data->directory = XtNewString(directory);
2103 cb_data->finish_callback = finish_callback;
2104 cb_data->callback_data = callback_data;
2107 /* mark the target directory as being modified in the directory cache */
2108 DirectoryBeginModify(host, directory);
2110 /* make a list of the operations to be done */
2111 /* Allocate memory for the DirUpdateStructure */
2112 cb_data->file_count = file_count;
2114 updates = (DirUpdate *)XtMalloc(file_count * sizeof(DirUpdate));
2116 /* Determine whether we are dealing with files or buffers */
2117 /* This affects how the updates structure is initialized */
2118 if (mode == MAKE_BUFFER)
2120 for (i=0; i< file_count; i++)
2122 /* just simply set the the updates structure with */
2123 /* the passed in file names */
2124 updates[i].file = XtNewString(file_set[i]);
2125 updates[i].bufferInfo.buf_ptr = buffer_set[i].buf_ptr;
2126 updates[i].bufferInfo.size = buffer_set[i].size;
2128 /* set unused updates fields to NOOP values */
2129 updates[i].time_sent = FALSE;
2130 updates[i].first_index = 0;
2131 updates[i].host = NULL;
2132 updates[i].directory = NULL;
2133 updates[i].app_man_dir = NULL;
2138 /* Seperate file names, directories, and hosts */
2139 /* when dealing with real files */
2140 for (i=0; i< file_count; i++)
2142 /* get the name of the source directory */
2143 ptr = strrchr(file_set[i], '/');
2146 if (ptr == file_set[i])
2151 source_dir = file_set[i];
2153 source_file = ptr + 1;
2157 source_dir = strdup(".");
2158 source_file = file_set[i];
2161 /* see if this directory is already in the list */
2162 for (j = 0; j < i; j++)
2163 if (strcmp(updates[j].host, host_set[i]) == 0 &&
2164 strcmp(updates[j].directory, source_dir) == 0)
2168 { /* already in the list */
2169 updates[i].host = updates[j].host;
2170 updates[i].directory = updates[j].directory;
2171 updates[i].app_man_dir = updates[j].app_man_dir;
2174 { /* not yet in the list */
2175 updates[i].host = XtNewString(host_set[i]);
2176 updates[i].directory = XtNewString(source_dir);
2177 updates[i].app_man_dir = NULL;
2182 if (((FileMgrData *)data)->toolbox)
2183 updates[i].app_man_dir =
2184 XtNewString(((FileMgrData *)data)->restricted_directory);
2188 /* mark the directory as being modified in the directory cache */
2189 if (mode == MOVE_FILE)
2190 DirectoryBeginModify(updates[i].host, updates[i].directory);
2192 updates[i].first_index = j;
2193 updates[i].time_sent = False;
2194 updates[i].operationStatus = False;
2195 updates[i].file = XtNewString(source_file);
2197 if (NULL != ptr) *ptr = '/';
2206 /* fork the process that does the actual work */
2210 DirectoryAbortModify(host, directory);
2211 for (i=0; i<file_count; i++)
2212 if (mode == MOVE_FILE && updates[i].first_index == i)
2213 DirectoryAbortModify(updates[i].host, updates[i].directory);
2216 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
2217 pname, getppid(), getpid(), errno, strerror(errno));
2223 DBGFORK(("%s: child forked, m2s %d s2m %d\n",
2224 pname, pipe_m2s[0], pipe_s2m[1]));
2226 close(pipe_m2s[1]); /* won't write to pipe_m2s */
2227 close(pipe_s2m[0]); /* won't read from pipe_s2m */
2229 if (desktopWindow != NULL)
2230 rc = FileMoveCopyProcessDesktop(pipe_s2m[1], pipe_m2s[0],
2231 directory, host, updates, file_count,
2232 mode, desktopWindow);
2234 rc = FileMoveCopyProcess(pipe_s2m[1], pipe_m2s[0], to_file, directory,
2235 host, updates, file_count, mode, NULL);
2237 DBGFORK(("%s: child exiting\n", pname));
2241 DBGFORK(("%s: forked child<%d>, m2s %d, s2m %d\n",
2242 pname, pid, pipe_m2s[1], pipe_s2m[0]));
2245 /* parent: set up callback to get the pipe data */
2246 close(pipe_m2s[0]); /* won't read from pipe_m2s */
2247 close(pipe_s2m[1]); /* won't write to pipe_s2m */
2249 cb_data->pipe_m2s = pipe_m2s[1];
2250 cb_data->pipe_s2m = pipe_s2m[0];
2251 cb_data->mode = mode;
2253 cb_data->child = pid;
2257 * We wait a certain amount of time for the background process to finish.
2258 * If it doesn't finish within that time, we do the rest asynchronously.
2261 /* set up fd set for select */
2262 FD_ZERO(&select_fds);
2265 /* compute until what time we want to wait */
2266 gettimeofday(&select_end, NULL);
2267 select_end.tv_sec += FILE_MOVE_COPY_WAIT_TIME;
2269 operation_done = False;
2272 /* determine how much time is left */
2273 gettimeofday(&now, NULL);
2274 select_timeout.tv_sec = select_end.tv_sec - now.tv_sec;
2275 select_timeout.tv_usec = select_end.tv_usec - now.tv_usec;
2276 if (select_timeout.tv_usec < 0)
2278 select_timeout.tv_sec--;
2279 select_timeout.tv_usec += 1000000;
2282 if ((int) select_timeout.tv_sec < 0)
2284 /* check if our time is up */
2285 DPRINTF(("FileMoveCopy: timed out; adding input callback\n"));
2286 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
2287 pipe_s2m[0], (XtPointer)XtInputReadMask,
2288 FileOpPipeCB, (XtPointer)cb_data);
2293 FD_SET(fd, &select_fds);
2294 #if defined(__hpux) && (OSMAJORVERSION <= 10) && (OSMINORVERSION < 2)
2295 rc = select(fd + 1, (int *)&select_fds, NULL, NULL, &select_timeout);
2297 rc = select(fd + 1, &select_fds, NULL, NULL, &select_timeout);
2299 if (rc < 0 && errno != EINTR)
2301 perror("select failed in FileMoveCopy");
2306 /* call FileOpPipeCB to read & process the data from the pipe */
2307 FileOpPipeCB((XtPointer)cb_data, &fd, NULL);
2308 DPRINTF(("FileMoveCopy: FileOpPipeCB -> fd = %d\n", fd));
2311 * If the background process is done, FileOpPipeCB sets fd
2312 * to zero (in case of success) or -1 (in case of failure).
2316 operation_done = (fd == 0);
2322 return operation_done;
2326 /*--------------------------------------------------------------------
2327 * FileMoveCopy, FileMoveCopyDesktop
2328 * External entry points for invoking _FileMoveCopy
2329 *------------------------------------------------------------------*/
2333 FileMgrData *file_mgr_data,
2340 unsigned int modifiers,
2341 void (*finish_callback)(),
2342 XtPointer callback_data)
2344 return _FileMoveCopy( (XtPointer)file_mgr_data, to_file, directory, host,
2345 host_set, file_set, NULL, file_count, modifiers, NULL,
2346 finish_callback, callback_data);
2351 FileMoveCopyDesktop(
2352 FileViewData *file_view_data,
2357 unsigned int modifiers,
2358 DesktopRec *desktopWindow,
2359 void (*finish_callback)(),
2360 XtPointer callback_data)
2362 return _FileMoveCopy ((XtPointer)file_view_data,
2377 /*====================================================================
2380 * Run a background process to rename an object.
2382 *==================================================================*/
2384 /*--------------------------------------------------------------------
2385 * ChangeIconNameProcess:
2386 * Main routine of the background process
2387 *------------------------------------------------------------------*/
2390 ChangeIconNameProcess(
2393 char *directory_name,
2397 char * full_name, * old_full_name, *dir_path;
2398 struct stat stat_buf;
2403 Tt_status tt_status;
2405 /* Check for uniqueness */
2406 full_name = ResolveLocalPathName(host_name, directory_name, new_name, home_host_name, &tt_status);
2407 if ( TT_OK != tt_status )
2409 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2410 pipe_msg = PIPEMSG_FILEOP_ERROR;
2411 write(pipe_fd, &pipe_msg, sizeof(short));
2416 if (lstat(full_name, &stat_buf) == 0)
2418 /* Name is not unique */
2419 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2420 pipe_msg = PIPEMSG_EXIST_ERROR;
2421 write(pipe_fd, &pipe_msg, sizeof(short));
2428 /* send a modified message back through the pipe */
2430 dir_path = ResolveLocalPathName(host_name, directory_name, NULL, home_host_name, &tt_status);
2431 if( TT_OK != tt_status )
2433 DPRINTF(("ChadengeIconNameProcess: sending exist error\n"));
2434 pipe_msg = PIPEMSG_FILEOP_ERROR;
2435 write(pipe_fd, &pipe_msg, sizeof(short));
2441 if (stat(dir_path, &stat_buf) == 0)
2442 modify_time = stat_buf.st_mtime;
2445 /* rename the file */
2446 old_full_name = ResolveLocalPathName(host_name, directory_name, old_name, home_host_name, &tt_status);
2447 if( TT_OK != tt_status )
2449 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2450 pipe_msg = PIPEMSG_FILEOP_ERROR;
2451 write(pipe_fd, &pipe_msg, sizeof(short));
2456 success = FileManip((Widget)pipe_fd, MOVE_FILE, old_full_name, full_name, TRUE,
2457 FileOpError, True, NOT_DESKTOP);
2458 XtFree( old_full_name );
2459 /* send a 'done' msg through the pipe */
2460 rc = success? 0: -1;
2463 pipe_msg = PIPEMSG_FILE_MODIFIED;
2464 write(pipe_fd, &pipe_msg, sizeof(short));
2465 write(pipe_fd, &modify_time, sizeof(long));
2467 DPRINTF(("ChangeIconNameProcess: sending DONE, rc %d\n", rc));
2468 pipe_msg = PIPEMSG_DONE;
2469 write(pipe_fd, &pipe_msg, sizeof(short));
2470 write(pipe_fd, &rc, sizeof(int));
2472 PipeWriteString(pipe_fd, full_name);
2473 XtFree( full_name );
2478 /*--------------------------------------------------------------------
2480 * Read and process data sent through the pipe.
2481 *------------------------------------------------------------------*/
2485 XtPointer client_data,
2489 ChangeIconCBData *cb_data = (ChangeIconCBData *)client_data;
2490 FileViewData *file_view_data = cb_data->file_view_data;
2491 DesktopRec *desktopWindow = cb_data->desktopWindow;
2494 DirectorySet *directory_set;
2495 FileMgrData *file_mgr_data = NULL;
2496 FileMgrRec *file_mgr_rec;
2500 char *title, *err_msg, *err_arg;
2506 Boolean desktop_changed;
2508 /* get widget for error messages */
2509 if (cb_data->desktop)
2511 msg_widget = XtParent(cb_data->w);
2515 directory_set = (DirectorySet *)file_view_data->directory_set;
2516 file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
2517 file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
2518 msg_widget = file_mgr_rec->file_window;
2521 /* read the msg from the pipe */
2523 n = PipeRead(*fd, &pipe_msg, sizeof(short));
2524 DPRINTF(("ChangeIconPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
2526 if (pipe_msg == PIPEMSG_FILE_MODIFIED)
2528 /* get modify time */
2529 PipeRead(*fd, &modify_time, sizeof(long));
2531 /* mark the old & new files as modified in the directory cache */
2532 if (modify_time != 0)
2533 DirectoryModifyTime(cb_data->host_name, cb_data->directory_name,
2535 DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
2537 DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
2542 if (pipe_msg == PIPEMSG_EXIST_ERROR)
2544 /* Name is not unique */
2545 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2546 if (cb_data->desktop)
2548 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.");
2549 err_msg = XtNewString(tmpStr);
2552 err_msg = XtNewString(GETMESSAGE(9,9, "A file with this name already exists.\nPlease choose a different name."));
2554 _DtMessage (msg_widget, title, err_msg, NULL, HelpRequestCB);
2559 else if (pipe_msg == PIPEMSG_FILEOP_ERROR)
2561 /* the rename failed */
2562 PipeRead(*fd, &rc, sizeof(int));
2563 err_msg = PipeReadString(*fd);
2564 err_arg = PipeReadString(*fd);
2565 FileOperationError(msg_widget, err_msg, err_arg);
2570 else if (pipe_msg == PIPEMSG_DONE)
2572 /* get the return code */
2573 PipeRead(*fd, &rc, sizeof(int));
2576 /* the rename was successful */
2577 full_name = PipeReadString(*fd);
2579 /* All went well, destroy the text field */
2580 XtUnmanageChild(cb_data->w);
2581 XtDestroyWidget(cb_data->w);
2583 /* Force the icon label to be updated immediately */
2584 if (cb_data->desktop)
2586 XmProcessTraversal(desktopWindow->iconGadget, XmTRAVERSE_CURRENT);
2587 desktopWindow->text = NULL;
2588 /* we'll catch this icon label in the loop after the else */
2592 file_mgr_data->renaming = NULL;
2594 label = XmStringCreateLocalized(cb_data->new_name);
2595 XtSetArg(args[0], XmNstring, label);
2596 XtSetValues(file_view_data->widget, args, 1);
2597 XmStringFree(label);
2598 XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
2599 XmUpdateDisplay (file_mgr_rec->file_window);
2602 * To prevent the positional data from becoming disassociated with
2603 * this file, we need to change the name in the positional data
2606 for (i = 0; i < file_mgr_data->num_objects; i++)
2608 if (strcmp(cb_data->old_name,
2609 file_mgr_data->object_positions[i]->name) == 0)
2612 XtFree(file_mgr_data->object_positions[i]->name);
2613 file_mgr_data->object_positions[i]->name =
2614 XtNewString(cb_data->new_name);
2621 * Check all desktop windows to see if they were linked to
2622 * the file we just renamed. If so, we need to change the
2623 * link in .dt/Desktop that points to it.
2625 * Note: We could do this in a background process, but we assume
2626 * that .dt/Desktop is local or, if it's remote and the remote server
2627 * is down, the user is screwed anyway. So we assume it's ok to do
2628 * blocking operations on .dt/Desktop in the main process.
2629 * Hence we go for the simpler solution here.
2631 desktop_changed = False;
2632 for (i = 0; i < desktop_data->numIconsUsed; i++)
2634 desktopWindow = desktop_data->desktopWindows[i];
2636 if (strcmp(cb_data->host_name, desktopWindow->host) == 0 &&
2637 strcmp(cb_data->directory_name, desktopWindow->dir_linked_to) == 0
2638 && strcmp(cb_data->old_name, desktopWindow->file_name) == 0)
2642 /* Force the icon label to be updated immediately */
2643 label = XmStringCreateLocalized(cb_data->new_name);
2644 XtSetArg(args[0], XmNstring, label);
2645 XtSetValues(desktopWindow->iconGadget, args, 1);
2646 XmStringFree(label);
2648 XtFree(desktopWindow->file_name);
2649 desktopWindow->file_name = XtNewString(cb_data->new_name);
2651 XtFree(desktopWindow->file_view_data->file_data->file_name);
2652 desktopWindow->file_view_data->file_data->file_name =
2653 XtNewString(cb_data->new_name);
2654 if( strcmp( desktopWindow->title, cb_data->old_name ) == 0 )
2656 XtFree( desktopWindow->title );
2657 desktopWindow->title = XtNewString( cb_data->new_name );
2660 GenerateShape(desktopWindow);
2662 RegisterIconDropsDT(desktopWindow);
2663 XmUpdateDisplay (desktopWindow->iconGadget);
2665 desktop_changed = True;
2669 if (desktop_changed)
2671 SaveDesktopInfo(NORMAL_RESTORE);
2679 fprintf(stderr, "Internal error in ChangeIconPipeCB: bad pipe_msg %d\n",
2682 /* arrange for the modified directory to be updated */
2683 DirectoryEndModify(cb_data->host_name, cb_data->directory_name);
2685 /* close the pipe and cancel the callback */
2689 /* free callback data */
2690 XtFree(cb_data->host_name);
2691 XtFree(cb_data->directory_name);
2692 XtFree(cb_data->old_name);
2693 XtFree(cb_data->new_name);
2694 XtFree((char *)cb_data);
2698 /*--------------------------------------------------------------------
2700 * Start the background process and set up callback for the pipe.
2701 *------------------------------------------------------------------*/
2707 FileViewData *file_view_data,
2708 DesktopRec *desktopWindow,
2710 char *directory_name)
2712 static char *pname = "_ChangeIconName";
2713 ChangeIconCBData *cb_data;
2725 int dirNameLength = strlen (directory_name);
2726 int maxFileNameLength = pathconf (directory_name, _PC_NAME_MAX);
2730 /* get the new name */
2731 XtSetArg(args[0], XmNvalue, &input_name);
2732 XtSetArg(args[1], XmNuserData, &old_name);
2733 XtGetValues(w, args, 2);
2735 new_name = (char *)_DtStripSpaces(XtNewString(input_name));
2736 length = strlen (new_name);
2739 /* new name must be a simple name, no path */
2741 if (DtStrchr (new_name, '/') != NULL)
2742 msg = XtNewString(GetSharedMessage(LOCAL_RENAME_ONLY_ERROR));
2743 #ifdef _CHECK_FOR_SPACES
2744 else if (DtStrchr (new_name, ' ') != NULL ||
2745 DtStrchr (new_name, '\t') != NULL)
2747 msg = XtNewString(GetSharedMessage(NO_SPACES_ALLOWED_ERROR));
2750 else if (length == 0 || strcmp(new_name, old_name) == 0)
2752 /* Noop; simply remove the text field */
2753 XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
2757 UnpostDTTextField();
2761 DirectorySet *directory_set =
2762 (DirectorySet *)file_view_data->directory_set;
2763 FileMgrData *file_mgr_data =
2764 (FileMgrData *)directory_set->file_mgr_data;
2765 FileMgrRec *file_mgr_rec =
2766 (FileMgrRec *)file_mgr_data->file_mgr_rec;
2767 file_mgr_rec->menuStates |= RENAME;
2768 UnpostTextField( file_mgr_data );
2769 file_mgr_data->renaming = NULL;
2773 /* Ensure the new name has length less than or equal to the maximum
2774 length that the system allows.
2775 If maxFileNameLength == -1 the file system is not supporting POSIX, use MAXNAMLEN
2777 else if( maxFileNameLength < -1 || ( maxFileNameLength == -1 && ( length > MAXNAMLEN || length + dirNameLength > MAX_PATH ) ) || ( maxFileNameLength > 0 && length > maxFileNameLength ) )
2779 msg = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2785 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2786 _DtMessage (XtParent (w), title, msg, NULL, HelpRequestCB);
2793 /* Check to see if the file has a representitive on the Desktop. */
2794 if (desktopWindow == NULL)
2796 for (i = 0; i < desktop_data->numIconsUsed; i++)
2798 if (strcmp(host_name,
2799 desktop_data->desktopWindows[i]->host) == 0 &&
2800 strcmp(directory_name,
2801 desktop_data->desktopWindows[i]->dir_linked_to) == 0 &&
2802 strcmp(old_name, desktop_data->desktopWindows[i]->
2803 file_view_data->file_data->file_name) == 0)
2805 desktopWindow = desktop_data->desktopWindows[i];
2811 if (desktopWindow != NULL)
2814 * There is a representation of this file on the desktop:
2815 * check if the there are any objects which match the new_name
2817 for (j = 0; j < desktop_data->numIconsUsed; j++)
2819 if (strcmp(new_name, desktop_data->desktopWindows[j]->
2820 file_view_data->file_data->file_name) == 0)
2822 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2824 tmpStr = GETMESSAGE(28,9, "An object with this name already exists on the Workspace.\nPlease choose a different name.");
2826 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.");
2827 msg = XtNewString(tmpStr);
2828 _DtMessage(XtParent (w), title, msg, NULL, HelpRequestCB);
2838 * Now we are ready to start the background process
2839 * that does the actual rename.
2842 /* set up callback data */
2843 cb_data = XtNew(ChangeIconCBData);
2845 cb_data->desktop = desktop;
2846 cb_data->file_view_data = file_view_data;
2847 cb_data->desktopWindow = desktopWindow;
2848 cb_data->host_name = XtNewString(host_name);
2849 cb_data->directory_name = XtNewString(directory_name);
2850 cb_data->old_name = XtNewString(old_name);
2851 cb_data->new_name = new_name;
2853 /* mark the directory as being modified in the directory cache */
2854 DirectoryBeginModify(host_name, directory_name);
2859 /* fork the process that does the actual work */
2863 DirectoryAbortModify(host_name, directory_name);
2865 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
2866 pname, getppid(), getpid(), errno, strerror(errno));
2872 DBGFORK(("%s: child forked, pipe %d\n", pname, pipe_fd[1]));
2874 close(pipe_fd[0]); /* child won't read from the pipe */
2876 rc = ChangeIconNameProcess(pipe_fd[1], host_name, directory_name,
2877 old_name, new_name);
2880 DBGFORK(("%s: child exiting\n", pname));
2885 DBGFORK(("%s: forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
2888 /* parent: set up callback to get the pipe data */
2889 close(pipe_fd[1]); /* parent won't write the pipe */
2891 cb_data->child = pid;
2893 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
2894 pipe_fd[0], (XtPointer)XtInputReadMask,
2895 ChangeIconPipeCB, (XtPointer)cb_data);
2902 XtPointer client_data,
2903 XmTextVerifyCallbackStruct * call_data)
2905 int value, size, increment, page;
2907 FileMgrData *file_mgr_data = (FileMgrData *)client_data;
2908 FileMgrRec *file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
2909 DirectorySet *directory_set = (DirectorySet *)(file_mgr_data->renaming->directory_set);
2911 if (call_data->reason == XmCR_MODIFYING_TEXT_VALUE ||
2912 call_data->reason == XmCR_MOVING_INSERT_CURSOR )
2915 /* x1 - x value of the text widget with respect to scroll window
2916 x2,y2 - x,y values of the cursor position (new) w.r.t text widget
2917 x3,y3 - x,y values of the cursor position (previous) w.r.t textW
2919 Position x1,x2,y2,x3,y3;
2920 /* width of the text widget */
2921 Dimension stringWidth;
2923 XtSetArg(args[0],XmNx,&x1);
2924 XtGetValues(w,args,1);
2926 if(XtIsManaged(file_mgr_rec->vertical_scroll_bar))
2927 SWwidth=(file_mgr_rec->scroll_window->core.width -
2928 file_mgr_rec->vertical_scroll_bar->core.width);
2930 SWwidth=file_mgr_rec->scroll_window->core.width;
2932 XmTextFieldPosToXY(w,call_data->newInsert,&x2,&y2);
2933 XmTextFieldPosToXY(w,call_data->currInsert,&x3,&y3);
2935 XtSetArg(args[0],XmNwidth,&stringWidth);
2936 XtGetValues(w,args,1);
2938 printf("\n x2=%d x1=%d x3=%d\n",x2,x1,x3);
2940 if ( (Dimension)(call_data->newInsert) < stringWidth )
2942 if( XtIsManaged(file_mgr_rec->horizontal_scroll_bar) )
2944 XmScrollBarGetValues( file_mgr_rec->horizontal_scroll_bar,
2945 &value, &size, &increment, &page);
2947 printf("\n value = %d",value);
2949 /* case where cursor is moved forward */
2953 XtSetArg (args[0], XmNmaximum, &max);
2954 XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
2955 if( (value < (max-size)) &&
2956 ((x1+x2) - value > 0 ) &&
2957 ( (Position)(((x1+x2) - value) +
2958 file_mgr_rec->vertical_scroll_bar->core.width) > (Position) SWwidth ) )
2960 if( (value+(x2-x3)) > (max-size) )
2964 XmScrollBarSetValues(
2965 file_mgr_rec->horizontal_scroll_bar,
2966 value, size, increment, page,True
2970 /* case where cursor is moved in reverse direction */
2971 else if( (x2-x3) < 0 )
2974 XtSetArg (args[0], XmNminimum, &min);
2975 XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
2976 if( (value > min) && ((Position)(x1+x3) < (Position)(value+
2977 file_mgr_rec->vertical_scroll_bar->core.width)) )
2979 if( (x2 <= 0) || ((value - (x3-x2)) < min) )
2983 XmScrollBarSetValues(file_mgr_rec->horizontal_scroll_bar,
2984 value, size, increment, page,True
2992 _ChangeIconName (w, False, file_mgr_data->renaming, NULL,
2993 file_mgr_data->host, directory_set->name);
3000 XtPointer client_data,
3001 XtPointer call_data)
3003 DesktopRec * desktopWindow = (DesktopRec *)client_data;
3005 _ChangeIconName (w, True, desktopWindow->file_view_data, desktopWindow,
3006 desktopWindow->host, desktopWindow->dir_linked_to);
3010 /*====================================================================
3013 * Run a background process to create a file or directory.
3015 *==================================================================*/
3017 /*--------------------------------------------------------------------
3019 * Build a host, directory, and file name path to be used as the
3020 * destination of a create, copy or move operation.
3021 *------------------------------------------------------------------*/
3034 strcpy(to_host, from_host);
3036 if (strncmp (new_name, "/", 1) == 0)
3038 strcpy(to_dir, new_name);
3042 if (strcmp(to_dir, "/") == 0)
3043 sprintf(to_dir, "%s%s", from_dir, new_name);
3045 sprintf(to_dir, "%s/%s", from_dir, new_name);
3048 ptr = strrchr(to_dir, '/');
3050 strcpy(to_file, ptr + 1);
3054 /*--------------------------------------------------------------------
3056 * Main routine of background process for MakeFile
3057 *------------------------------------------------------------------*/
3068 struct stat stat_buf;
3074 Tt_status tt_status;
3076 /* assume success */
3079 /* get the full name of the file/dir to be created */
3080 to = ResolveLocalPathName(to_host, to_dir, to_file, home_host_name, &tt_status);
3084 /* check if a file/dir with the same name already exists */
3085 else if (lstat (to, &stat_buf) == 0)
3088 /* now create the file/dir */
3091 /* send a modified message back through the pipe */
3093 dir_path = ResolveLocalPathName(to_host, to_dir, NULL, home_host_name, &tt_status);
3094 if (stat(dir_path, &stat_buf) == 0)
3095 modify_time = stat_buf.st_mtime;
3098 pipe_msg = PIPEMSG_FILE_MODIFIED;
3099 write(pipe_fd, &pipe_msg, sizeof(short));
3100 write(pipe_fd, &modify_time, sizeof(long));
3103 if (type == DtDIRECTORY)
3105 if (mkdir (to, (int) DtFILE_DIR_CREATION_MASK) != 0)
3113 mode = DtFILE_DATA_CREATION_MASK;
3115 mode = DtFILE_OTHER_CREATION_MASK;
3117 if ((fnew = creat(to, (int) mode)) < 0)
3124 /* send a 'done' msg through the pipe */
3125 pipe_msg = PIPEMSG_DONE;
3126 DPRINTF(("MakeFileProcess: sending DONE, rc %d\n", rc));
3127 write(pipe_fd, &pipe_msg, sizeof(short));
3128 write(pipe_fd, &rc, sizeof(int));
3129 PipeWriteString(pipe_fd, to);
3137 /*--------------------------------------------------------------------
3139 * Read and process data sent through the pipe.
3140 *------------------------------------------------------------------*/
3144 XtPointer client_data,
3148 MakeFileCBData *cb_data = (MakeFileCBData *)client_data;
3155 /* read the msg from the pipe */
3157 n = PipeRead(*fd, &pipe_msg, sizeof(short));
3159 if (pipe_msg == PIPEMSG_FILE_MODIFIED)
3161 /* get modify time */
3162 PipeRead(*fd, &modify_time, sizeof(long));
3164 /* mark the file updated in the directory cache */
3165 if (modify_time != 0)
3166 DirectoryModifyTime(cb_data->to_host, cb_data->to_dir, modify_time);
3167 DirectoryFileModified(cb_data->to_host, cb_data->to_dir,
3172 if (pipe_msg == PIPEMSG_DONE)
3174 PipeRead(*fd, &rc, sizeof(int));
3175 full_name = PipeReadString(*fd);
3179 fprintf(stderr, "Internal error in MakeFilePipeCB: bad pipe_msg %d\n",
3185 DPRINTF(("MakeFilePipeCB: n %d, pipe_msg %d, rc %d\n", n, pipe_msg, rc));
3187 /* arrange for the modified directory to be updated */
3188 DirectoryEndModify(cb_data->to_host, cb_data->to_dir);
3190 /* close the pipe and cancel the callback */
3194 /* Store away the newly created file so we later on we can
3198 MakeFileDoneData * data = (MakeFileDoneData *)cb_data->callback_data;
3199 DialogCallbackStruct * call_struct = data->call_struct;
3200 FileMgrData * file_mgr_data = call_struct->file_mgr_data;
3202 file_mgr_data->scrollToThisDirectory = cb_data->to_dir;
3203 file_mgr_data->scrollToThisFile = cb_data->to_file;
3206 /* call the callback routine */
3207 if (cb_data->finish_callback)
3208 (*cb_data->finish_callback)(cb_data->callback_data, full_name, rc);
3210 /* free callback data */
3212 XtFree(cb_data->to_host);
3214 /* Don't free to_dir and to_file. We used this to remember
3215 which file so later on we can scroll to it.
3216 XtFree(cb_data->to_dir);
3217 XtFree(cb_data->to_file);
3220 XtFree((char *)cb_data);
3224 /*--------------------------------------------------------------------
3226 * Start the background process and set up callback for the pipe.
3227 *------------------------------------------------------------------*/
3233 char *directory_name,
3236 void (*finish_callback)(),
3237 XtPointer callback_data)
3239 static char *pname = "MakeFile";
3240 MakeFileCBData *cb_data;
3241 char to_host[MAX_PATH];
3242 char to_dir[MAX_PATH];
3243 char to_file[MAX_PATH];
3248 /* get host & path of the target file */
3249 GetTarget(host_name, directory_name, new_name, to_host, to_dir, to_file);
3251 /* mark the target directory as being modified in the directory cache */
3252 DirectoryBeginModify(to_host, to_dir);
3254 /* parent: set up callback to get the pipe data */
3255 cb_data = XtNew(MakeFileCBData);
3256 cb_data->to_host = XtNewString(to_host);
3257 cb_data->to_dir = XtNewString(to_dir);
3258 cb_data->to_file = XtNewString(to_file);
3259 cb_data->finish_callback = finish_callback;
3260 cb_data->callback_data = callback_data;
3265 /* fork the process that does the actual work */
3269 DirectoryAbortModify(to_host, to_dir);
3271 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
3272 pname, getppid(), getpid(), errno, strerror(errno));
3279 DBGFORK(("%s: child forked, pipe %d\n", pname, pipe_fd[1]));
3281 close(pipe_fd[0]); /* child won't read from the pipe */
3283 rc = MakeFileProcess(pipe_fd[1], to_host, to_dir, to_file, type);
3286 DBGFORK(("%s: child exiting\n", pname));
3291 DBGFORK(("%s: forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
3293 /* parent: set up callback to get the pipe data */
3294 close(pipe_fd[1]); /* parent won't write the pipe */
3296 cb_data->child = pid;
3298 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
3299 pipe_fd[0], (XtPointer)XtInputReadMask,
3300 MakeFilePipeCB, (XtPointer)cb_data);
3304 /*=============================================================
3306 * The following routines handle the creation of files from
3307 * buffers: MakeFilesFromBuffers and MakeFilesFromBuffersDT
3310 *=============================================================*/
3313 MakeFilesFromBuffers(
3314 FileMgrData *file_mgr_data,
3319 BufferInfo *buffer_set,
3321 void (*finish_callback)(),
3322 XtPointer callback_data)
3324 return _FileMoveCopy ((XtPointer)file_mgr_data, NULL, directory, host,
3325 host_set, file_set, buffer_set, num_of_buffers,
3326 NULL, NULL, finish_callback, callback_data);
3331 MakeFilesFromBuffersDT(
3332 FileViewData *file_view_data,
3336 BufferInfo *buffer_set,
3338 DesktopRec *desktopWindow,
3339 void (*finish_callback)(),
3340 XtPointer callback_data)
3342 return _FileMoveCopy ((XtPointer)file_view_data, NULL, directory,
3344 host_set, file_set, buffer_set, num_of_buffers,
3345 NULL, desktopWindow, finish_callback, callback_data);
3349 /*====================================================================
3351 * CreateFileFromBuffer
3352 * Routine to create a file from a buffer
3354 *==================================================================*/
3358 CreateFileFromBuffer(int pipe_s2m,
3360 char *fully_qualified_name,
3367 Boolean BufferIsExecutable=FALSE;
3368 char *err_msg, *err_arg, *tmpStr;
3369 char *format_str, *strerror_str;
3370 int format_param_len=20;
3376 /* Set the permissions depending if buffer is a */
3377 /* file or an execuatable */
3378 if (_DtIsBufferExecutable(buffer,size))
3380 mode = S_IRUSR | S_IWUSR | S_IXUSR |
3381 S_IRGRP | S_IWGRP | S_IXGRP |
3382 S_IROTH | S_IWOTH | S_IXOTH;
3386 mode = S_IRUSR | S_IWUSR |
3391 /* Create the target file */
3392 if ((fnew = open(fully_qualified_name, O_CREAT| O_WRONLY, mode)) < 0)
3394 DPRINTF(("CreateBufferFromFile: Could not create %s\n",
3395 fully_qualified_name));
3401 /* Write the buffer to the target file */
3402 if ((rc = write(fnew, buffer, size)) < 0 )
3404 DPRINTF (("CreateBufferFromFile: Could not write buffer to %s\n",
3405 fully_qualified_name));
3411 DPRINTF (("CreateBuffeFromFile: Target file %s created\n",
3412 fully_qualified_name));
3422 tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
3423 err_msg = XtNewString(tmpStr);
3424 err_arg = XtNewString(fully_qualified_name);
3426 DPRINTF (("CreateBufferFromFile: EACCESS errno is %d\n",errno));
3429 err_msg = strerror(savedError);
3432 DPRINTF (("CreateBufferFromFile: %s\n", err_msg));
3435 /* Write error message on pipe so */
3436 /* that the parent process will */
3437 /* display a dialog */
3438 PipeWriteErrmsg(pipe_s2m, rc, err_msg, err_arg);
3439 if (err_msg) XtFree(err_msg);
3440 if (err_arg) XtFree(err_arg);
3451 * DisplayDuplicateOpError - Used in FileOpPipeCallback when a duplicate
3452 * operation like move/copy/link a file onto the same file is performed,
3453 * this routine gets called and displays an error message.
3457 DisplayDuplicateOpError(
3458 FileOpCBData *cb_data,
3462 char *msgptr,*err_msg,*title,*tchar;
3463 Widget dialogwidget;
3465 if (cb_data->mode == MOVE_FILE)
3467 if(cb_data->callback_data == NULL)
3468 if(initiating_view == NULL)
3472 title = XtCalloc(1,strlen(GETMESSAGE(9,73,"Move"))+
3473 strlen(GETMESSAGE(9,94,"Error"))+5);
3474 tchar = XtNewString(GETMESSAGE(9,73,"Move"));
3475 sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3477 err_msg = GETMESSAGE(11,135,"Cannot move object %s onto itself");
3480 else if (cb_data->mode == COPY_FILE)
3482 title = XtCalloc(1,strlen(GETMESSAGE(9,72,"Copy"))+
3483 strlen(GETMESSAGE(9,94,"Error"))+5);
3484 tchar = XtNewString(GETMESSAGE(9,72,"Copy"));
3485 sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3487 if(cb_data->callback_data == NULL)
3489 if(cb_data->file_mgr_data && cb_data->file_mgr_data->toolbox)
3495 err_msg = GETMESSAGE(11,136,"Cannot copy object %s onto itself");
3499 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");
3504 title = XtCalloc(1,strlen(GETMESSAGE(9,74,"Link"))+
3505 strlen(GETMESSAGE(9,94,"Error"))+5);
3506 tchar = XtNewString(GETMESSAGE(9,74,"Link"));
3507 sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3509 if(cb_data->callback_data == NULL)
3511 err_msg = GETMESSAGE(11,137,"Cannot link object %s onto itself");
3515 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");
3519 msgptr = XtCalloc(1,strlen(err_msg)+strlen(cb_data->updates[index].file)+10);
3520 sprintf(msgptr,err_msg,cb_data->updates[index].file);
3522 if(cb_data->callback_data)
3523 dialogwidget = ((RenameDoneData *)(cb_data->callback_data))->w;
3525 dialogwidget = toplevel;
3526 _DtMessage (dialogwidget,title, msgptr, NULL, HelpRequestCB);
3533 /*==============================================================
3535 * appendErrorMessage
3537 * if "arg" is not null, "new" is assumed to include %s
3538 * "message" is re-allocated and so will have a different
3539 * address than when the function was called
3541 * usage: errorMsg = appendErrorMessage(errorMsg,errStr,file);
3543 *==============================================================
3547 appendErrorMessage(String message, String new, String arg)
3552 newMessage = XtNewString(new);
3555 newMessage = XtMalloc(strlen(new) + strlen(arg) + 1);
3556 sprintf(newMessage,new,arg);
3559 if (message == NULL)
3561 message = XtRealloc(message, (strlen(newMessage) + 2));
3565 message = XtRealloc(message, (strlen(message) + strlen(newMessage) + 2));
3567 strcat(message,newMessage);
3568 strcat(message,"\n");
3574 } /* end appendErrorMessage */
3577 DisplayErrorMessage(
3585 localstr = (char *) XtMalloc(strlen(errMsg)+strlen(from)+strlen(tdir) + 10 );
3586 sprintf(localstr,errMsg,tdir,from);
3587 PipeWriteErrmsg(pipe_s2m, -1, localstr, NULL);
3595 char filename [MAX_PATH];
3597 int slen = strlen(source_path);
3599 if(slen > strlen(dest_path))
3601 strcpy (filename, dest_path);
3602 cptr = strchr(&filename[slen-1],'/');
3605 return ((strcmp(source_path,filename) == 0)?True:False);