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 libraries 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>
84 #include <sys/select.h>
87 #if defined(_AIX)|| defined(hpux)
97 #include <Xm/MwmUtil.h>
99 #include <Xm/ScrollBar.h>
100 #include <X11/ShellP.h>
101 #include <X11/Shell.h>
102 #include <X11/Xutil.h>
103 #include <X11/Xatom.h>
106 #include <X11/extensions/shape.h>
110 #include <Dt/IconP.h>
111 #include <Dt/IconFile.h>
112 #include <Dt/Action.h>
113 #include <Dt/Connect.h>
115 #include <Dt/DtNlUtils.h>
116 #include <Dt/HourGlass.h>
117 #include <Dt/SharedProcs.h>
122 #include "SharedProcs.h"
130 #include "SharedMsgs.h"
131 #include "sharedFuncs.h"
134 /* Static Function declarations */
136 static Boolean CreateFileFromBuffer(
139 char *fully_qualified_name,
142 static String appendErrorMessage(
146 static void DisplayErrorMessage(
151 static Boolean IsInParentDir(char *from,char *to);
153 /* the amount of time we wait for a file move/copy to complete */
154 /* @@@ should make this a resource */
155 #define FILE_MOVE_COPY_WAIT_TIME 2
158 /* types of messages sent through the pipe */
159 #define PIPEMSG_FILEOP_ERROR 1
160 #define PIPEMSG_EXIST_ERROR 2
161 #define PIPEMSG_OTHER_ERROR 3
162 #define PIPEMSG_CONFIRM 4
163 #define PIPEMSG_TARGET_TIME 5
164 #define PIPEMSG_FILE_MODIFIED 6
165 #define PIPEMSG_DONE 7
166 #define PIPEMSG_REPLACE_RENAME 8
167 #define PIPEMSG_REPLACE_RENAME_SAME 9
168 #define PIPEMSG_REPLACE_MERGE 10
169 #define PIPEMSG_MULTICOLLIDE 11
170 #define PIPEMSG_MULTICOLLIDE_SAME 12
171 #define PIPEMSG_MOVE_TO_SAME_DIR 13
173 /* the following messages are also defined & used in OverWrite.c */
174 #define PIPEMSG_CANCEL 101
175 #define PIPEMSG_PROCEED 102
176 #define PIPEMSG_MERGE 103
177 #define PIPEMSG_REPLACE_BUFFER 104
178 #define PIPEMSG_RENAME_BUFFER 105
179 #define PIPEMSG_MULTI_PROCEED 106
181 extern int G_dropx,G_dropy;
183 /* callback data for file move/copy/link */
188 BufferInfo bufferInfo;
191 Boolean operationStatus;
198 FileMgrData *file_mgr_data;
199 FileMgrRec *file_mgr_rec;
200 FileViewData *file_view_data;
201 DesktopRec *desktopWindow;
202 int pipe_m2s; /* pipe main to slave */
203 int pipe_s2m; /* pipe slave to main */
209 void (*finish_callback)();
210 XtPointer callback_data;
215 /* callback data for file rename */
220 FileViewData *file_view_data;
221 DesktopRec *desktopWindow;
223 char *directory_name;
230 /* callback data for create file/directory */
236 void (*finish_callback)();
237 XtPointer callback_data;
243 DisplayDuplicateOpError(FileOpCBData *cb_data,int index);
247 /*====================================================================
249 * Routine for sending data through a pipe
251 *==================================================================*/
253 /*--------------------------------------------------------------------
255 * Read data from the pipe
256 *------------------------------------------------------------------*/
264 static int whined_fd = -1;
270 rc = read(fd, (char *)buf + n, len - n);
273 else if (rc < 0 && errno == EINTR)
283 "PipeRead: broken pipe, ppid=%d pid=%d fd=%d\n",
284 getppid(), getpid(), fd);
289 perror("dtfile: read failed in PipeRead");
300 /*--------------------------------------------------------------------
302 * write a string to the pipe
303 *------------------------------------------------------------------*/
313 oldPipe = (void (*)())signal(SIGPIPE, SIG_IGN);
320 if (write(fd, &len, sizeof(short)) < 0) {
325 sent = write(fd, s, len);
327 signal(SIGPIPE, oldPipe);
333 /*--------------------------------------------------------------------
335 * read a string from the pipe
336 *------------------------------------------------------------------*/
347 if (PipeRead(fd, &len, sizeof(short)) != sizeof(short))
354 s = (char *)XtMalloc(len + 1);
355 if (PipeRead(fd, s, len) != len)
366 /*--------------------------------------------------------------------
368 * write an error message to the pipe
369 *------------------------------------------------------------------*/
378 short pipe_msg = PIPEMSG_FILEOP_ERROR;
380 DPRINTF(("PipeWriteErrmsg: sending error %d \"%s\"\n", rc, msg));
382 write(fd, &pipe_msg, sizeof(short));
383 write(fd, &rc, sizeof(int));
384 PipeWriteString(fd, msg);
385 PipeWriteString(fd, arg);
391 /*====================================================================
394 * Run a background process to move/copy/link files dropped
395 * on a dtfile window or icon.
397 *==================================================================*/
399 /*--------------------------------------------------------------------
400 * moveCopyLinkCancel:
401 * Cancel-button callback for overwrite confirmation dialog
402 *------------------------------------------------------------------*/
404 int filop_confirm_fd = -1; /* @@@ can't we pass this in client_data? */
409 XtPointer client_data,
410 XtPointer call_data )
412 const int rc = PIPEMSG_CANCEL;
414 /* close the dialog */
415 XtUnmanageChild((Widget)client_data);
416 XmUpdateDisplay((Widget)client_data);
417 XtDestroyWidget((Widget)client_data);
419 /* send return code through the pipe to the background proc */
420 write(filop_confirm_fd, &rc, sizeof(int));
421 filop_confirm_fd = -1;
425 /*--------------------------------------------------------------------
427 * Ok-button callback for overwrite confirmation dialog
428 *------------------------------------------------------------------*/
433 XtPointer client_data,
434 XtPointer call_data )
436 const int rc = PIPEMSG_PROCEED;
438 /* close the dialog */
439 XtUnmanageChild((Widget)client_data);
440 XmUpdateDisplay((Widget)client_data);
441 XtDestroyWidget((Widget)client_data);
443 /* send affirmative return code through the pipe to the background proc */
444 write(filop_confirm_fd, &rc, sizeof(int));
445 filop_confirm_fd = -1;
449 /*--------------------------------------------------------------------
451 * Error handler for FileManip when called in the background process
452 *------------------------------------------------------------------*/
460 int pipe_fd = (int) (intptr_t) w; /* @@@ Hack! @@@
461 In the background process we call FileManip with
462 the file descriptor for the pipe instead of a
463 widget id. We rely on the fact that FileManip
464 never uses the widget as a widget, but only
465 passes it to the error handler. */
467 /* write the error message to the pipe */
468 PipeWriteErrmsg(pipe_fd, -1, message1, message2);
472 /*--------------------------------------------------------------------
474 * Send a message through the pipe that informs the main process
475 * that we are about to modify a directory or that a file has been
477 *------------------------------------------------------------------*/
492 struct stat stat_buf;
495 /* if first operation on target dir, send timestamp */
498 if (stat(to, &stat_buf) == 0)
500 modify_time = stat_buf.st_mtime;
501 pipe_msg = PIPEMSG_TARGET_TIME;
502 write(pipe_fd, &pipe_msg, sizeof(short));
503 write(pipe_fd, &modify_time, sizeof(long));
507 /* if first operation on source dir, get timestamp of source dir */
509 j = updates[i].first_index;
510 if (mode == MOVE_FILE && !updates[j].time_sent)
514 dir_path = ResolveLocalPathName(updates[i].host,
515 updates[i].directory,
520 if (stat(dir_path, &stat_buf) == 0)
521 modify_time = stat_buf.st_mtime;
523 updates[j].time_sent = True;
526 /* send the modify message */
527 pipe_msg = PIPEMSG_FILE_MODIFIED;
528 write(pipe_fd, &pipe_msg, sizeof(short));
529 write(pipe_fd, &i, sizeof(int));
530 write(pipe_fd, &modify_time, sizeof(long));
531 PipeWriteString(pipe_fd, target_file);
534 /*--------------------------------------------------------------------
535 * FileMoveCopyProcess:
536 * Main routine of the background process
538 * This routine has two basic modes of operation:
539 * It is given a list of source files and a target directory,
540 * and performs an operation on the source files. This mode
541 * is used for drag & drop operations where a user can
542 * select multiple source files and then drop them on a
543 * target directory to either move, copy, or copy-as-link
544 * the source files to the target directory. The source
545 * and target directories must be different.
546 * It is given a single source file and a target file. The
547 * target can be either a directory or a file. This mode
548 * is used for menu-intiated move, copy, or copy-as-link
549 * operations. The source and target directories can be
551 * The source file(s) are given in updates; the destination is
552 * in host, dirctory, to_file. If to_file is NULL, the
553 * first mode (drag & drop) is assumed, otherwise assume
554 * menu-initiated mode.
556 *------------------------------------------------------------------*/
568 DesktopRec *desktopWindow)
570 char * target_dir, * from, * to;
571 int i, j, rc, result;
572 Boolean return_val = False;
575 char *tmpStr, *target_file;
576 struct stat stat_buf, from_stat_buf;
580 int *sameIndex = NULL, *sameConfirmType = NULL;
581 Boolean first_op = True;
585 String permissionErrors = NULL;
586 Boolean targetChecked = FALSE;
587 Boolean targetError = FALSE;
588 Boolean CopyError=FALSE,MoveError1=FALSE,MoveError2=FALSE;
589 char *CopyString=NULL,*MoveString1=NULL,*MoveString2=NULL;
592 /* Get the fully qualified destination path. */
593 target_dir = (char *)ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
594 if( TT_OK != tt_status )
596 char msg1[2*MAX_PATH];
598 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
599 directory, host, host);
601 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
602 directory, host, host);
604 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
605 pipe_msg = PIPEMSG_FILEOP_ERROR;
607 write(pipe_s2m, &pipe_msg, sizeof(short));
608 write(pipe_s2m, &rc, sizeof(int));
612 DtEliminateDots(target_dir);
614 for (i = 0; i < file_count; i++)
618 /* get full name of the source file, if just */
619 /* dealing with regular files */
620 if (mode != MAKE_BUFFER)
622 from = ResolveLocalPathName(updates[i].host,
623 updates[i].directory,
629 char msg1[2*MAX_PATH];
632 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
633 updates[i].directory, updates[i].host, updates[i].host);
635 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
636 updates[i].directory, updates[i].host, updates[i].host);
638 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
642 /* do some extra error checking if a target filename is specified */
643 /* this is meant for the case of a menu-initiated operation */
646 /* Verify that the target directory already exists */
647 if ( (stat(target_dir, &stat_buf) != 0) ||
648 (! S_ISDIR(stat_buf.st_mode) ) )
653 GETMESSAGE(11,41,"The folder\n%s\ndoes not exist."));
654 PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
662 /* check for a drop of a directory onto itself */
663 if (updates[i].app_man_dir)
665 char *temp_dir = XtNewString(target_dir);
667 temp_dir = _DtResolveAppManPath(temp_dir, updates[i].app_man_dir);
668 if (mode == MOVE_FILE && strcmp(temp_dir, from) == 0)
673 GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
674 PipeWriteErrmsg( pipe_s2m, -1, msg, temp_dir );
683 else if (mode == MOVE_FILE && strcmp(target_dir, from) == 0)
688 GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
689 PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
695 else if (mode == MOVE_FILE && stat(from, &stat_buf) == 0 &&
696 S_ISDIR(stat_buf.st_mode) && DirectoryBusy(from))
700 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."));
702 PipeWriteErrmsg( pipe_s2m, -1, msg, from );
710 /* for copy operations, check for read permission on the source file */
711 /* the error message is appended to a list and dealt with later */
712 /* the current file is not processed */
713 if (mode == COPY_FILE)
714 if (CheckAccess(from,R_OK) == -1)
719 /* 'errno' is not giving correct results like 'ENOENT' in order to
720 use it here, may be because of the other system calls in
723 if (stat(from, &sbuf) < 0)
724 tmpStr = (GETMESSAGE(28,13,"Object:\n\n %s\n\n does not exist in the file system"));
726 tmpStr = GetSharedMessage(CANT_READ_ERROR);
728 permissionErrors = appendErrorMessage(permissionErrors, tmpStr, from);
735 if (strcmp(target_dir, "/") == 0)
737 target_file = (char *)XtMalloc(strlen(target_dir) +
738 strlen(updates[i].file) + 1);
739 sprintf(target_file, "%s%s", target_dir, updates[i].file);
743 target_file = (char *)XtMalloc(strlen(target_dir) +
744 strlen(updates[i].file) + 2);
745 sprintf(target_file, "%s/%s", target_dir, updates[i].file);
750 if (strcmp(target_dir, "/") == 0)
752 target_file = (char *)XtMalloc(strlen(target_dir) +
753 strlen(to_file) + 1);
754 sprintf(target_file, "%s%s", target_dir, to_file);
758 target_file = (char *)XtMalloc(strlen(target_dir) +
759 strlen(to_file) + 2);
760 sprintf(target_file, "%s/%s", target_dir, to_file);
763 if (updates[i].app_man_dir)
764 target_file = _DtResolveAppManPath(target_file,
765 updates[i].app_man_dir);
766 /* check if source and target files are the same.
767 * if they are the same, set a flag noting that they are. If the
768 * the operation is a move, it doesn't make any sense to move it, so
769 * send back a MOVE_TO_SAME_DIR msg.
772 if ((mode != MAKE_BUFFER) && (strcmp(target_file, from) == 0))
774 if (mode == MOVE_FILE && stat(target_file, &stat_buf) == 0)
776 if(S_ISDIR(stat_buf.st_mode))
778 pipe_msg = PIPEMSG_MOVE_TO_SAME_DIR;
779 write(pipe_s2m, &pipe_msg, sizeof(short));
780 write(pipe_s2m, &i, sizeof(int));
789 /* for copy operations, check for write permission on the target */
791 /* for move operations, check for write permission on the source and */
792 /* target directories */
793 /* the error message is appended to a list and dealt with later */
794 /* the current file is not processed */
795 if (mode == COPY_FILE)
797 if (CheckAccess(target_dir,W_OK) == -1)
801 if(CopyString == NULL)
802 CopyString = XtNewString(from);
805 CopyString = (char *) XtRealloc(CopyString,strlen(CopyString)+
807 strcat(CopyString,"\n");
808 strcat(CopyString,from);
813 else if (mode == MOVE_FILE)
815 Boolean error = FALSE;
816 if (targetChecked || CheckAccess(target_dir,W_OK) == -1)
819 if(MoveString1 == NULL)
820 MoveString1 = XtNewString(from);
823 MoveString1=(char *)XtRealloc(MoveString1,strlen(MoveString1)+
825 strcat(MoveString1,"\n");
826 strcat(MoveString1,from);
828 error = targetError = TRUE;
829 targetChecked = TRUE;
831 if (CheckAccess(_DtPName(from),W_OK) == -1)
834 if(MoveString2 == NULL)
835 MoveString2 = XtNewString(from);
838 MoveString2 = (char *)XtRealloc(MoveString2,strlen(MoveString2)+
840 strcat(MoveString2,"\n");
841 strcat(MoveString2,from);
845 if (error || targetError)
852 /* check if target file already exists */
853 if (stat(target_file, &stat_buf) == 0)
855 /* target file already exists: remember and deal with it later */
856 if(mode == MOVE_FILE && S_ISDIR(stat_buf.st_mode)
857 && DirectoryBusy(target_file))
861 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."));
863 PipeWriteErrmsg( pipe_s2m, -1, msg, target_file );
869 if (sameIndex == NULL)
871 sameIndex = (int *)XtMalloc(file_count*sizeof(int));
872 sameConfirmType = (int *)XtMalloc(file_count*sizeof(int));
874 sameIndex[sameCount] = i;
876 /* determine how to set the pipe message */
877 if (mode == MAKE_BUFFER)
879 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
883 stat(from, &from_stat_buf);
884 if ( S_ISDIR(from_stat_buf.st_mode) &&
885 S_ISDIR(stat_buf.st_mode) &&
888 /* if its a directory and there already is a directory of the
889 * same name the user may want to merge the directories into
890 * one directory. But if the directory to be copied is being
891 * copied into the same directory it came from, it doesn't make
892 * sense to merge. Set up message to REPLACE_RENAME_SAME
893 * indicating it is being copied from and to the same directory
896 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
898 sameConfirmType[sameCount] = PIPEMSG_REPLACE_MERGE;
902 /* If the copy/move/link is to the same directory, set up a
903 * different case then when the op is happening from different
907 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
909 sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
911 } /* endif mode != MAKE_BUFFER */
915 if (mode != MAKE_BUFFER)
916 XtFree ((char *) from);
918 XtFree ((char *) target_file);
920 } /* endif targetfile already exists */
922 if ((isContainer = (to_file == NULL)))
928 * Note: it is important that SendModifyMsg is called before any
929 * changes are made to either the source or target directory.
930 * This is because SendModifyMsg is supposed to obtain and send
931 * the time stamp of the directories BEFORE any operation. If
932 * the wrong timestamp is sent, the window will be updated and
933 * redrawn twice instead of just once.
935 SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, i,
939 if (mode == MAKE_BUFFER)
941 /* Call CreateFileFromBuffer */
942 return_val = CreateFileFromBuffer(pipe_s2m, to,
944 updates[i].bufferInfo.buf_ptr,
945 updates[i].bufferInfo.size);
949 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
950 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
952 FileOpError, True, DESKTOP);
954 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
956 FileOpError, True, NOT_DESKTOP);
957 XtFree( (char *) from );
960 XtFree ((char *) target_file);
964 if(CopyError == TRUE)
967 errMsg = GETMESSAGE(11,48,
968 "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");
969 DisplayErrorMessage(pipe_s2m,errMsg,CopyString,target_dir);
971 permissionErrors = NULL;
975 if(MoveError1 == TRUE)
978 errMsg = GETMESSAGE(11,49,
979 "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");
980 DisplayErrorMessage(pipe_s2m,errMsg,MoveString1,target_dir);
982 permissionErrors = NULL;
986 if(MoveError2 == TRUE)
989 errMsg = GETMESSAGE(11,50,
990 "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");
991 DisplayErrorMessage(pipe_s2m,errMsg,MoveString2,target_dir);
993 permissionErrors = NULL;
999 /* If there were any permissions errors, show the error message */
1000 if (permissionErrors != NULL)
1002 PipeWriteErrmsg(pipe_s2m, -1, permissionErrors, NULL);
1003 XtFree(permissionErrors);
1008 * Now deal with with the cases where we found that the target file
1015 * @@@ Note: The code below for sending a target-time pipe message
1016 * at this point shouldn't really be necessary.
1017 * The problem is that the target directory time stamp MUST be
1018 * obtained BEFORE any changes are made to the directory;
1019 * otherwise, the window will be updated and redrawn twice instead
1020 * of just once. Unfortunately, currently, if the user chooses to
1021 * replace or rename the existing file, the rename or delete
1022 * operation is done in the main process (inside the
1023 * replace_rename_ok_callback in Overwrite.c), instead of here in
1024 * the child process where it belongs (the main process shouldn't
1025 * do any file system operations because they could block for a
1026 * long time on a slow server). If and when overwrite dialog code
1027 * is fixed, the code below can be deleted; the target-time
1028 * message will then be sent by the call to SendModifyMsg further
1029 * below after the call to PipeRead.
1033 if (stat(target_dir, &stat_buf) == 0)
1035 modify_time = stat_buf.st_mtime;
1036 pipe_msg = PIPEMSG_TARGET_TIME;
1037 write(pipe_s2m, &pipe_msg, sizeof(short));
1038 write(pipe_s2m, &modify_time, sizeof(long));
1043 /* send message to main process to display dialog (and possibly remove/rename files) */
1044 if (file_count == 1)
1046 if (to_file == NULL) /* note target_file here is only file name, above it is full path */
1047 target_file = updates[sameIndex[0]].file;
1049 target_file = to_file;
1050 pipe_msg = sameConfirmType[0];
1051 DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
1052 write(pipe_s2m, &pipe_msg, sizeof(short));
1053 DPRINTF(("FileMoveCopyProcess: sending: mode %d directory \"%s\" file \"%s\" \n",
1054 mode, directory, target_file));
1055 write(pipe_s2m, &mode, sizeof(int));
1056 PipeWriteString(pipe_s2m, directory);
1057 PipeWriteString(pipe_s2m, target_file);
1061 int processCount=file_count-errorCount;
1063 /* If the copy/move/link is to the same directory, set up a
1064 * different case then when the op is happening from different
1068 pipe_msg = PIPEMSG_MULTICOLLIDE_SAME;
1070 pipe_msg = PIPEMSG_MULTICOLLIDE;
1072 DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
1073 write(pipe_s2m, &pipe_msg, sizeof(short));
1074 DPRINTF(("FileMoveCopyProcess: sending: mode %d processCount %d sameCount %d directory \"%s\"\n",
1075 mode, processCount, sameCount, directory));
1076 write(pipe_s2m, &mode, sizeof(int));
1077 write(pipe_s2m, &processCount, sizeof(int));
1078 write(pipe_s2m, &sameCount, sizeof(int));
1079 PipeWriteString(pipe_s2m, directory);
1080 DPRINTF(("FileMoveCopyProcess: sending %d filename strings\n", sameCount));
1081 for (i = 0; i < sameCount; i++)
1082 PipeWriteString(pipe_s2m, updates[sameIndex[i]].file);
1085 /* wait for reply from main process */
1087 PipeRead(pipe_m2s, &rc, sizeof(int));
1088 DPRINTF(("FileMoveCopyProcess: woke up after confirm, rc %d\n", rc));
1089 if (rc != PIPEMSG_CANCEL)
1091 /* affirmative reply: do the operation */
1092 for(i = 0; i < sameCount; i++)
1095 if (rc != PIPEMSG_RENAME_BUFFER)
1097 SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, j,
1101 if (rc == PIPEMSG_MULTI_PROCEED)
1104 PipeRead(pipe_m2s, &opvalue, sizeof(int));
1109 if (mode != MAKE_BUFFER)
1111 from = ResolveLocalPathName( updates[j].host,
1112 updates[j].directory,
1116 if( TT_OK != tt_status )
1118 char msg1[2*MAX_PATH];
1121 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1122 updates[j].directory, updates[j].host,
1125 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1126 updates[j].directory, updates[j].host,
1129 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
1136 if ( (isContainer = (to_file == NULL)) )
1142 to = (char *)XtMalloc(strlen(target_dir) + strlen(to_file) + 2);
1143 sprintf(to, "%s/%s", target_dir, to_file);
1148 /* check the return code for type of message and */
1149 /* perform the appropriate action */
1154 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
1155 return_val = FileManip((Widget) (intptr_t) pipe_s2m, MERGE_DIR, from,
1157 FileOpError, True, DESKTOP);
1159 return_val = FileManip((Widget) (intptr_t) pipe_s2m, MERGE_DIR, from,
1161 FileOpError, True, NOT_DESKTOP);
1164 case PIPEMSG_REPLACE_BUFFER:
1165 target_file = (char *)XtMalloc(strlen(to) + strlen(updates[j].file)
1167 sprintf(target_file, "%s/%s", to, updates[j].file);
1168 DPRINTF (("file is %s",updates[j].file));
1169 return_val = CreateFileFromBuffer(pipe_s2m,
1172 updates[j].bufferInfo.buf_ptr,
1173 updates[j].bufferInfo.size);
1174 XtFree((char *)target_file);
1177 case PIPEMSG_RENAME_BUFFER:
1179 renamed_file = PipeReadString(pipe_m2s);
1181 SendModifyMsg(pipe_s2m, mode, first_op, to, updates, j, renamed_file);
1182 target_file = (char *)XtMalloc(strlen(to) + strlen(renamed_file)
1184 sprintf(target_file, "%s/%s", to, renamed_file);
1185 DPRINTF(("file is %s",renamed_file));
1186 return_val = CreateFileFromBuffer(pipe_s2m,
1189 updates[j].bufferInfo.buf_ptr,
1190 updates[j].bufferInfo.size);
1191 XtFree((char *) target_file);
1196 if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
1197 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
1198 isContainer,FileOpError, True,
1202 /* if the operation (move/copy/link) is happening from
1203 * and to the same folder, we want to create a new name
1204 * for the object for which the operation is happening
1209 char path[MAX_PATH], newDir[MAX_PATH],
1214 generate_NewPath(path,path);
1215 split_path(path, newDir, newFile);
1216 toFile = (char *)XtMalloc(strlen(newDir) +
1217 strlen(newFile) + 3);
1218 strcpy(toFile, newDir);
1219 strcat(toFile, "/");
1220 strcat(toFile, newFile);
1222 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from,
1223 toFile, False, FileOpError,
1229 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from,
1230 to, isContainer, FileOpError,
1235 if (to_file != NULL)
1237 XtFree ((char *) to);
1241 }/*end if rc != PIPEMSG_CANCEL*/
1244 XtFree((char *)sameIndex);
1246 XtFree((char *)sameConfirmType);
1247 sameConfirmType = NULL;
1249 } /* endif sameCount != 0 */
1252 pipe_msg = PIPEMSG_DONE;
1253 if (rc != PIPEMSG_CANCEL)
1254 rc = return_val? 0: -1;
1257 write(pipe_s2m, &pipe_msg, sizeof(short));
1258 write(pipe_s2m, &rc, sizeof(int));
1260 XtFree ((char *) target_dir);
1267 /*--------------------------------------------------------------------
1268 * FileMoveCopyProcessDesktop:
1269 * Main routine of the background process that handles files
1270 * dropped in desktop icons.
1271 *------------------------------------------------------------------*/
1274 FileMoveCopyProcessDesktop(
1282 DesktopRec *desktopWindow)
1286 Boolean first_op = True;
1287 Boolean return_val = False;
1289 Tt_status tt_status;
1291 /* Get the fully qualified destination path. */
1292 to = ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
1293 if( TT_OK != tt_status )
1295 char msg1[2*MAX_PATH];
1297 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1298 directory, host, host);
1300 sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1301 directory, host, host);
1303 PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
1304 pipe_msg = PIPEMSG_FILEOP_ERROR;
1306 write(pipe_s2m, &pipe_msg, sizeof(short));
1307 write(pipe_s2m, &rc, sizeof(int));
1310 DtEliminateDots(to);
1312 for (i = 0; i < file_count; i++)
1314 /* get full name of the source file, if just */
1315 /* dealing with regular files */
1316 if (mode != MAKE_BUFFER)
1318 from = ResolveLocalPathName(updates[i].host,
1319 updates[i].directory,
1325 char msg[2*MAX_PATH];
1328 sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1329 updates[i].directory, updates[i].host, updates[i].host);
1331 sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1332 updates[i].directory, updates[i].host, updates[i].host);
1334 PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
1336 else if (strcmp(to, from) == 0)
1338 char msg[2*MAX_PATH];
1340 sprintf(msg,GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"),to);
1341 PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
1342 XtFree ((char *) from);
1345 } /* end if dealing with regular files */
1348 SendModifyMsg(pipe_s2m, mode, first_op, to, updates, i, updates[i].file);
1352 if (mode == MAKE_BUFFER)
1356 if (strcmp(to, "/") == 0)
1358 target_file = (char *) XtMalloc(strlen(to) +
1359 strlen(updates[i].file) + 1);
1360 sprintf(target_file, "%s%s", to, updates[i].file);
1364 target_file = (char *) XtMalloc(strlen(to) +
1365 strlen(updates[i].file) + 2);
1366 sprintf(target_file, "%s/%s", to, updates[i].file);
1369 return_val = CreateFileFromBuffer(pipe_s2m,
1372 updates[i].bufferInfo.buf_ptr,
1373 updates[i].bufferInfo.size);
1377 return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to, TRUE,
1378 FileOpError, True, DESKTOP);
1384 pipe_msg = PIPEMSG_DONE;
1385 rc = return_val? 0: -1;
1386 write(pipe_s2m, &pipe_msg, sizeof(short));
1387 write(pipe_s2m, &rc, sizeof(int));
1389 XtFree ((char *) to);
1395 RemoveIconFromWorkspace( char * iconName,
1398 DesktopRec *desktopWin;
1400 char fileName[MAX_PATH];
1403 for(i = 0; i < desktop_data->numIconsUsed; i++)
1405 desktopWin = desktop_data->desktopWindows[i];
1407 if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
1408 sprintf( fileName, "/%s", desktopWin->file_name );
1410 sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
1412 if( strcmp( fileName, iconName ) == 0 )
1416 Screen *currentScreen;
1418 char *workspace_name;
1420 screen = XDefaultScreen(XtDisplay(desktopWin->shell));
1422 XScreenOfDisplay(XtDisplay(desktopWin->shell), screen);
1423 rootWindow = RootWindowOfScreen(currentScreen);
1425 if(DtWsmGetCurrentWorkspace(XtDisplay(desktopWin->shell),
1426 rootWindow, &pCurrent) == Success)
1428 XGetAtomName (XtDisplay(desktopWin->shell), pCurrent);
1430 workspace_name = XtNewString("One");
1432 if( strcmp( workspace_name, desktopWin->workspace_name ) == 0 )
1434 RemoveDT( desktopWin->shell, (XtPointer) desktopWin,
1439 XtFree( desktopWin->dir_linked_to );
1440 desktopWin->dir_linked_to = XtNewString( targetDir );
1443 XtFree(workspace_name);
1449 ChangeWorkspaceIconLink( FileMgrData *fmd,
1454 DesktopRec *desktopWin;
1457 char fileName[MAX_PATH];
1460 for(i = 0; i < desktop_data->numIconsUsed; i++)
1462 desktopWin = desktop_data->desktopWindows[i];
1464 if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
1465 sprintf( fileName, "/%s", desktopWin->file_name );
1467 sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
1469 DtEliminateDots(fileName);
1470 if( strcmp( fileName, iconName ) == 0 )
1471 dirp = XtNewString(targetDir);
1472 else if(IsInParentDir(iconName,desktopWin->dir_linked_to))
1474 int index = strlen(iconPdir);
1475 char *tptr = desktopWin->dir_linked_to;
1477 dirp = XtCalloc( 1, strlen(targetDir)+ strlen(&tptr[index])+1);
1478 sprintf(dirp,"%s%s",targetDir,&tptr[index]);
1483 FileViewData *file_view_data;
1484 DirectorySet *directory_set;
1485 FileMgrData *file_mgr_data;
1486 Tt_status tt_status;
1487 char * full_dir_name;
1489 file_view_data = desktopWin->file_view_data;
1490 directory_set = (DirectorySet *)file_view_data->directory_set;
1491 file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
1494 fmd = file_mgr_data;
1495 FreeFileData( file_view_data->file_data, True );
1496 file_view_data->file_data = NULL;
1498 XtFree( desktopWin->dir_linked_to );
1499 desktopWin->dir_linked_to = XtNewString( dirp );
1500 DtEliminateDots(desktopWin->dir_linked_to);
1504 if (fmd->restricted_directory == NULL)
1505 desktopWin->restricted_directory = NULL;
1507 desktopWin->restricted_directory =
1508 XtNewString(fmd->restricted_directory);
1510 if (fmd->helpVol == NULL)
1511 desktopWin->helpVol = NULL;
1513 desktopWin->helpVol = XtNewString(fmd->helpVol);
1515 desktopWin->helpVol = XtNewString( fmd->helpVol );
1516 desktopWin->view = fmd->view;
1517 desktopWin->order = fmd->order;
1518 desktopWin->direction = fmd->direction;
1519 desktopWin->positionEnabled = fmd->positionEnabled;
1520 desktopWin->toolbox = fmd->toolbox;
1523 full_dir_name = ResolveLocalPathName(desktopWin->host,
1528 if( TT_OK == tt_status )
1530 FileData2 file_data2;
1534 DtEliminateDots (full_dir_name);
1537 IsToolBox = fmd->toolbox;
1541 if (strcmp(desktopWin->file_name, ".") == 0)
1542 ReadFileData2(&file_data2, full_dir_name, NULL, IsToolBox);
1544 ReadFileData2(&file_data2, full_dir_name, desktopWin->file_name,
1547 file_view_data->file_data = FileData2toFileData(&file_data2, &n);
1548 XtFree(full_dir_name);
1549 full_dir_name = NULL;
1552 ((DirectorySet *)file_view_data->directory_set)->name =
1555 SaveDesktopInfo(NORMAL_RESTORE);
1562 /*--------------------------------------------------------------------
1564 * Read and process data sent through the pipe.
1565 *------------------------------------------------------------------*/
1569 XtPointer client_data,
1573 FileOpCBData *cb_data = (FileOpCBData *)client_data;
1576 char *title, *err_msg, *err_arg;
1577 char *directory, *file, *target_file;
1581 int nSelected, nCollisions;
1583 static int status = 0;
1585 static ActionAreaItem replace_rename_actionItems[] = {
1586 {"Ok", 9, 27, NULL, NULL}, /* changed later based on mode */
1587 {"Cancel", 9, 28, replace_rename_cancel_callback, NULL},
1588 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_REN},
1591 ActionAreaDefn replace_renameActions = {
1592 XtNumber(replace_rename_actionItems),
1593 1, /* Cancel is default action */
1594 replace_rename_actionItems
1597 static ActionAreaItem replace_merge_actionItems[] = {
1598 {"Ok", 9, 27, replace_merge_ok_callback, NULL},
1599 {"Cancel", 9, 28, replace_merge_cancel_callback, NULL}, /* changed below depending on mode */
1600 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_MRG},
1603 ActionAreaDefn replace_mergeActions = {
1604 XtNumber(replace_merge_actionItems),
1605 1, /* Cancel is default action */
1606 replace_merge_actionItems
1609 static ActionAreaItem multicollide_actionItems[] = {
1610 {"Ok", 9, 27, NULL, NULL}, /* changed later based on Mode */
1611 {"Cancel", 9, 28, multicollide_cancel_callback, NULL}, /* changed below depending on mode */
1612 {"Help", 9, 29, HelpRequestCB, HELP_FILE_MANAGER_MULTI},
1615 ActionAreaDefn multicollideActions = {
1616 XtNumber(multicollide_actionItems),
1617 1, /* Cancel is default action */
1618 multicollide_actionItems
1622 /* Initialize Action Area structures based on mode */
1623 /* Set the appropriate callback routines */
1624 mode = cb_data->mode;
1628 replace_rename_actionItems[0].callback =
1629 buffer_replace_rename_ok_callback;
1630 multicollide_actionItems[0].callback =
1631 buffer_multicollide_ok_callback;
1634 replace_rename_actionItems[0].callback =
1635 replace_rename_ok_callback;
1636 multicollide_actionItems[0].callback =
1637 multicollide_ok_callback;
1642 /* read the next msg from the pipe */
1644 n = PipeRead(*fd, &pipe_msg, sizeof(short));
1645 DPRINTF(("FileOpPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
1650 case PIPEMSG_FILEOP_ERROR:
1651 PipeRead(*fd, &rc, sizeof(int));
1652 err_msg = PipeReadString(*fd);
1653 err_arg = PipeReadString(*fd);
1654 if (cb_data->desktop)
1655 FileOperationError(cb_data->file_view_data->widget,
1659 /* routine can be called with a NULL file_mgr_rec, use the
1660 * top level widget if this is the case.
1662 if(cb_data->file_mgr_rec)
1663 FileOperationError(cb_data->file_mgr_rec->file_window,
1666 FileOperationError(toplevel, err_msg, err_arg);
1670 if(cb_data->callback_data)
1672 RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
1673 ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
1674 ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
1676 status = PIPEMSG_FILEOP_ERROR;
1679 case PIPEMSG_CONFIRM:
1680 err_msg = PipeReadString(*fd);
1681 title = XtNewString(GETMESSAGE(9,11, "File Manager - Move/Copy/Link Warning"));
1682 filop_confirm_fd = cb_data->pipe_m2s;
1683 _DtMessageDialog(toplevel, title, err_msg, NULL, TRUE,
1684 moveCopyLinkCancel, moveCopyLinkOK, NULL,
1685 HelpRequestCB, False, QUESTION_DIALOG);
1690 case PIPEMSG_REPLACE_RENAME_SAME:
1691 /* filename collision: display replace/rename dialog */
1692 PipeRead(*fd, &mode, sizeof(int));
1693 directory = PipeReadString(*fd);
1694 file = PipeReadString(*fd);
1695 /* routine can be called with a NULL file_mgr_rec, use the
1696 * top level widget if this is the case.
1699 /* the object is copying/linking itself to the same folder. Want
1700 * to indicate the to the ok dialog and the building of the replace
1703 replace_rename_actionItems[0].data = (XtPointer)True;
1704 if(cb_data->file_mgr_rec)
1705 create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
1706 mode, directory, file,
1708 replace_renameActions, True);
1710 create_replace_rename_dialog(toplevel,
1711 mode, directory, file,
1713 replace_renameActions, True);
1718 case PIPEMSG_REPLACE_RENAME:
1719 /* filename collision: display replace/rename dialog */
1720 PipeRead(*fd, &mode, sizeof(int));
1721 directory = PipeReadString(*fd);
1722 file = PipeReadString(*fd);
1723 /* routine can be called with a NULL file_mgr_rec, use the
1724 * top level widget if this is the case.
1726 replace_rename_actionItems[0].data = (XtPointer)NULL;
1727 if(cb_data->file_mgr_rec)
1728 create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
1729 mode, directory, file,
1731 replace_renameActions, False);
1733 create_replace_rename_dialog(toplevel,
1734 mode, directory, file,
1736 replace_renameActions, False);
1741 case PIPEMSG_REPLACE_MERGE:
1742 /* filename collision: display replace/merge dialog */
1743 PipeRead(*fd, &mode, sizeof(int));
1744 directory = PipeReadString(*fd);
1745 file = PipeReadString(*fd);
1746 /* routine can be called with a NULL file_mgr_rec, use the
1747 * top level widget if this is the case.
1749 if(cb_data->file_mgr_rec)
1750 create_replace_merge_dialog(cb_data->file_mgr_rec->shell,
1751 mode, directory, file,
1753 replace_mergeActions);
1755 create_replace_merge_dialog(toplevel,
1756 mode, directory, file,
1758 replace_mergeActions);
1763 case PIPEMSG_MULTICOLLIDE_SAME:
1764 /* filename collision: display multicollide dialog */
1765 PipeRead(*fd, &mode, sizeof(int));
1766 PipeRead(*fd, &nSelected, sizeof(int));
1767 PipeRead(*fd, &nCollisions, sizeof(int));
1768 directory = PipeReadString(*fd);
1769 file = XtMalloc( MAX_PATH );
1770 fileList = (String *) XtMalloc(nCollisions * sizeof(String)); /* de- allocated in dialog's callback functions */
1771 for (i = 0; i < nCollisions; i++)
1773 fileList[i] = PipeReadString(*fd);
1775 /* routine can be called with a NULL file_mgr_rec, use the
1776 * top level widget if this is the case.
1779 /* the object is copying/linking itself to the same folder. Want
1780 * to indicate the to the ok dialog and the building of the replace
1783 multicollide_actionItems[0].data = (XtPointer)True;
1784 if(cb_data->file_mgr_rec)
1785 create_multicollide_dialog(cb_data->file_mgr_rec->shell,
1786 mode, nSelected, nCollisions,
1787 directory, fileList,
1789 multicollideActions, True);
1791 create_multicollide_dialog(toplevel,
1792 mode, nSelected, nCollisions,
1793 directory, fileList,
1795 multicollideActions, True);
1799 case PIPEMSG_MULTICOLLIDE:
1800 /* filename collision: display multicollide dialog */
1801 PipeRead(*fd, &mode, sizeof(int));
1802 PipeRead(*fd, &nSelected, sizeof(int));
1803 PipeRead(*fd, &nCollisions, sizeof(int));
1804 directory = PipeReadString(*fd);
1805 file = XtMalloc( MAX_PATH );
1806 fileList = (String *) XtMalloc(nCollisions * sizeof(String)); /* de-allocated in dialog's callback functions */
1807 for (i = 0; i < nCollisions; i++)
1809 fileList[i] = PipeReadString(*fd);
1811 /* routine can be called with a NULL file_mgr_rec, use the
1812 * top level widget if this is the case.
1814 multicollide_actionItems[0].data = (XtPointer)NULL;
1815 if(cb_data->file_mgr_rec)
1816 create_multicollide_dialog(cb_data->file_mgr_rec->shell,
1817 mode, nSelected, nCollisions,
1818 directory, fileList,
1820 multicollideActions, False);
1822 create_multicollide_dialog(toplevel,
1823 mode, nSelected, nCollisions,
1824 directory, fileList,
1826 multicollideActions, False);
1831 case PIPEMSG_TARGET_TIME:
1832 /* get the modify time and update the directory cache */
1833 PipeRead(*fd, &modify_time, sizeof(long));
1834 DirectoryModifyTime(cb_data->host, cb_data->directory, modify_time);
1837 case PIPEMSG_MOVE_TO_SAME_DIR:
1838 /* get the update index */
1839 PipeRead(*fd, &i, sizeof(int));
1840 cb_data->updates[i].operationStatus = True;
1841 DisplayDuplicateOpError((void *) cb_data,i);
1842 status = PIPEMSG_MOVE_TO_SAME_DIR;
1843 if(cb_data->callback_data)
1845 RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
1846 ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
1847 ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
1851 case PIPEMSG_FILE_MODIFIED:
1852 /* get the update index and modify time */
1853 PipeRead(*fd, &i, sizeof(int));
1854 PipeRead(*fd, &modify_time, sizeof(long));
1855 target_file = PipeReadString(*fd);
1856 DPRINTF (("PIPEMSG_FILE_MODIFIED %s\n", target_file));
1858 /* mark the file updated in the cached target directory */
1859 DirectoryFileModified(cb_data->host, cb_data->directory,
1862 if (cb_data->mode == MOVE_FILE)
1864 /* mark the file updated in the cached source directory */
1865 if (modify_time != 0)
1866 DirectoryModifyTime(cb_data->updates[i].host,
1867 cb_data->updates[i].directory,
1869 DirectoryFileModified(cb_data->updates[i].host,
1870 cb_data->updates[i].directory,
1871 cb_data->updates[i].file);
1873 cb_data->updates[i].operationStatus = True;
1874 XtFree(target_file); target_file = NULL;
1878 PipeRead(*fd, &rc, sizeof(int));
1883 fprintf(stderr, "Internal error in FileOpPipeCB: bad pipe_msg %d\n",
1891 char tmpDir[MAX_PATH];
1893 DPRINTF(("FileOpPipeCB: done, rc %d\n", rc));
1895 /* close the pipe and cancel the callback */
1896 close(cb_data->pipe_m2s);
1897 close(cb_data->pipe_s2m);
1901 *fd = (rc == 0)? 0: -1;
1903 /* arrange for modified directories to be updated */
1904 DirectoryEndModify(cb_data->host, cb_data->directory);
1906 /* Reposition the objects which have been modified */
1907 if(!cb_data->finish_callback && cb_data->file_mgr_data)
1911 /* Do this only if it is the current directory and Random placement
1913 if(cb_data->file_mgr_data->positionEnabled != RANDOM_OFF && strcmp(
1914 cb_data->directory,cb_data->file_mgr_data->current_directory)==0)
1916 file_set = (char **) XtCalloc(1,cb_data->file_count*sizeof(char *));
1917 for(i=0;i<cb_data->file_count;i++)
1919 if(cb_data->updates[i].operationStatus == True)
1920 file_set[actual_count++] = cb_data->updates[i].file;
1922 RepositionIcons(cb_data->file_mgr_data, file_set,actual_count,
1923 G_dropx, G_dropy, True);
1924 XtFree((char *)file_set);
1929 for(i = 0; i < desktop_data->numWorkspaces; i++)
1930 DeselectAllDTFiles(desktop_data->workspaceData[i]);
1932 for (i = 0; i < cb_data->file_count; i++)
1934 char fileName[MAX_PATH];
1936 /* Scroll the window to show the created object, since we
1937 cannot keep scrolling for each object we just do it for
1938 one object and we do it in case of Drag/Drop, but not
1939 for Select.MoveTo/CopyTo ... */
1941 if(!i && cb_data->callback_data == NULL)
1945 if(cb_data && cb_data->file_mgr_data)
1947 fmd = cb_data->file_mgr_data;
1948 fmd->scrollToThisDirectory = XtNewString(cb_data->directory);
1949 fmd->scrollToThisFile = XtNewString(cb_data->updates[i].file);
1952 if (cb_data->updates[i].first_index == i)
1954 if (cb_data->mode == MOVE_FILE)
1956 DirectoryEndModify(cb_data->updates[i].host,
1957 cb_data->updates[i].directory);
1958 if( strcmp( cb_data->updates[i].directory, "/" ) == 0 )
1961 sprintf( tmpDir, "%s", cb_data->updates[i].directory );
1964 if( cb_data->updates[i].host )
1965 XtFree( cb_data->updates[i].host );
1966 if( cb_data->updates[i].directory )
1967 XtFree( cb_data->updates[i].directory );
1968 if( cb_data->updates[i].app_man_dir )
1969 XtFree( cb_data->updates[i].app_man_dir );
1972 if( cb_data->mode == MOVE_FILE )
1974 sprintf( fileName, "%s/%s", tmpDir, cb_data->updates[i].file );
1975 if( cb_data->updates[i].operationStatus == True )
1977 if( status == PIPEMSG_MOVE_TO_SAME_DIR )
1979 RemoveIconFromWorkspace( fileName, cb_data->directory );
1981 else if( status != PIPEMSG_FILEOP_ERROR )
1983 ChangeWorkspaceIconLink(cb_data->file_mgr_data, fileName,
1984 cb_data->directory,tmpDir );
1986 /* If it is workspace drag and drop and the move operation
1987 is not because of Select.MoveTo menu option */
1989 if(initiating_view == NULL && cb_data->callback_data == NULL)
1991 sprintf( fileName, "%s/%s", cb_data->directory,
1992 cb_data->updates[i].file );
1993 DtEliminateDots(fileName);
1994 RemoveIconFromWorkspace( fileName, cb_data->directory );
2000 XtFree(cb_data->updates[i].file);
2005 /* call the callback routine */
2006 if (cb_data->finish_callback)
2007 (*cb_data->finish_callback)(cb_data->callback_data, rc);
2009 /* free the callback data */
2010 XtFree((char *)cb_data->updates);
2011 XtFree((char *)cb_data->directory);
2012 XtFree((char *)cb_data->host);
2013 XtFree(client_data);
2018 /*--------------------------------------------------------------------
2020 * Start the background process and set up callback for the pipe.
2021 *------------------------------------------------------------------*/
2031 BufferInfo *buffer_set,
2033 unsigned int modifiers,
2034 DesktopRec *desktopWindow,
2035 void (*finish_callback)(),
2036 XtPointer callback_data)
2038 static char *pname = "_FileMoveCopy";
2040 FileOpCBData *cb_data;
2044 char *source_dir = NULL;
2045 char *source_file = NULL;
2051 struct timeval now, select_end, select_timeout;
2052 Boolean operation_done;
2056 /* Determine the type of operation: move, copy, or link */
2057 /* or creating buffers */
2058 if (buffer_set != NULL)
2064 modifiers &= ~Button2Mask;
2065 if (modifiers == ShiftMask)
2067 else if (modifiers == ControlMask)
2073 /* set up the callback data structure */
2074 cb_data = XtNew(FileOpCBData);
2075 cb_data->desktop = (desktopWindow != NULL);
2076 if (cb_data->desktop)
2078 cb_data->file_mgr_data = NULL;
2079 cb_data->file_mgr_rec = NULL;
2080 cb_data->file_view_data = (FileViewData *)data;
2081 cb_data->desktopWindow = desktopWindow;
2087 cb_data->file_mgr_data = (FileMgrData *)data;
2088 cb_data->file_mgr_rec =
2089 (FileMgrRec *) ((FileMgrData *)data)->file_mgr_rec;
2093 cb_data->file_mgr_data = NULL;
2094 cb_data->file_mgr_rec = NULL;
2096 cb_data->file_view_data = NULL;
2097 cb_data->desktopWindow = NULL;
2099 cb_data->mode = mode;
2100 cb_data->host = XtNewString(host);
2101 cb_data->directory = XtNewString(directory);
2102 cb_data->finish_callback = finish_callback;
2103 cb_data->callback_data = callback_data;
2106 /* mark the target directory as being modified in the directory cache */
2107 DirectoryBeginModify(host, directory);
2109 /* make a list of the operations to be done */
2110 /* Allocate memory for the DirUpdateStructure */
2111 cb_data->file_count = file_count;
2113 updates = (DirUpdate *)XtMalloc(file_count * sizeof(DirUpdate));
2115 /* Determine whether we are dealing with files or buffers */
2116 /* This affects how the updates structure is initialized */
2117 if (mode == MAKE_BUFFER)
2119 for (i=0; i< file_count; i++)
2121 /* just simply set the the updates structure with */
2122 /* the passed in file names */
2123 updates[i].file = XtNewString(file_set[i]);
2124 updates[i].bufferInfo.buf_ptr = buffer_set[i].buf_ptr;
2125 updates[i].bufferInfo.size = buffer_set[i].size;
2127 /* set unused updates fields to NOOP values */
2128 updates[i].time_sent = FALSE;
2129 updates[i].first_index = 0;
2130 updates[i].host = NULL;
2131 updates[i].directory = NULL;
2132 updates[i].app_man_dir = NULL;
2137 /* Seperate file names, directories, and hosts */
2138 /* when dealing with real files */
2139 for (i=0; i< file_count; i++)
2141 /* get the name of the source directory */
2142 ptr = strrchr(file_set[i], '/');
2145 if (ptr == file_set[i])
2150 source_dir = file_set[i];
2152 source_file = ptr + 1;
2157 source_file = file_set[i];
2160 /* see if this directory is already in the list */
2161 for (j = 0; j < i; j++)
2162 if (strcmp(updates[j].host, host_set[i]) == 0 &&
2163 strcmp(updates[j].directory, source_dir) == 0)
2167 { /* already in the list */
2168 updates[i].host = updates[j].host;
2169 updates[i].directory = updates[j].directory;
2170 updates[i].app_man_dir = updates[j].app_man_dir;
2173 { /* not yet in the list */
2174 updates[i].host = XtNewString(host_set[i]);
2175 updates[i].directory = XtNewString(source_dir);
2176 updates[i].app_man_dir = NULL;
2181 if (((FileMgrData *)data)->toolbox)
2182 updates[i].app_man_dir =
2183 XtNewString(((FileMgrData *)data)->restricted_directory);
2187 /* mark the directory as being modified in the directory cache */
2188 if (mode == MOVE_FILE)
2189 DirectoryBeginModify(updates[i].host, updates[i].directory);
2191 updates[i].first_index = j;
2192 updates[i].time_sent = False;
2193 updates[i].operationStatus = False;
2194 updates[i].file = XtNewString(source_file);
2196 if (NULL != ptr) *ptr = '/';
2205 /* fork the process that does the actual work */
2209 DirectoryAbortModify(host, directory);
2210 for (i=0; i<file_count; i++)
2211 if (mode == MOVE_FILE && updates[i].first_index == i)
2212 DirectoryAbortModify(updates[i].host, updates[i].directory);
2215 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
2216 pname, getppid(), getpid(), errno, strerror(errno));
2222 DBGFORK(("%s: child forked, m2s %d s2m %d\n",
2223 pname, pipe_m2s[0], pipe_s2m[1]));
2225 close(pipe_m2s[1]); /* won't write to pipe_m2s */
2226 close(pipe_s2m[0]); /* won't read from pipe_s2m */
2228 if (desktopWindow != NULL)
2229 rc = FileMoveCopyProcessDesktop(pipe_s2m[1], pipe_m2s[0],
2230 directory, host, updates, file_count,
2231 mode, desktopWindow);
2233 rc = FileMoveCopyProcess(pipe_s2m[1], pipe_m2s[0], to_file, directory,
2234 host, updates, file_count, mode, NULL);
2236 DBGFORK(("%s: child exiting\n", pname));
2240 DBGFORK(("%s: forked child<%d>, m2s %d, s2m %d\n",
2241 pname, pid, pipe_m2s[1], pipe_s2m[0]));
2244 /* parent: set up callback to get the pipe data */
2245 close(pipe_m2s[0]); /* won't read from pipe_m2s */
2246 close(pipe_s2m[1]); /* won't write to pipe_s2m */
2248 cb_data->pipe_m2s = pipe_m2s[1];
2249 cb_data->pipe_s2m = pipe_s2m[0];
2250 cb_data->mode = mode;
2253 * We wait a certain amount of time for the background process to finish.
2254 * If it doesn't finish within that time, we do the rest asynchronously.
2257 /* set up fd set for select */
2258 FD_ZERO(&select_fds);
2261 /* compute until what time we want to wait */
2262 gettimeofday(&select_end, NULL);
2263 select_end.tv_sec += FILE_MOVE_COPY_WAIT_TIME;
2265 operation_done = False;
2268 /* determine how much time is left */
2269 gettimeofday(&now, NULL);
2270 select_timeout.tv_sec = select_end.tv_sec - now.tv_sec;
2271 select_timeout.tv_usec = select_end.tv_usec - now.tv_usec;
2272 if (select_timeout.tv_usec < 0)
2274 select_timeout.tv_sec--;
2275 select_timeout.tv_usec += 1000000;
2278 if ((int) select_timeout.tv_sec < 0)
2280 /* check if our time is up */
2281 DPRINTF(("FileMoveCopy: timed out; adding input callback\n"));
2282 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
2283 pipe_s2m[0], (XtPointer)XtInputReadMask,
2284 FileOpPipeCB, (XtPointer)cb_data);
2289 FD_SET(fd, &select_fds);
2290 #if defined(__hpux) && (OSMAJORVERSION <= 10) && (OSMINORVERSION < 2)
2291 rc = select(fd + 1, (int *)&select_fds, NULL, NULL, &select_timeout);
2293 rc = select(fd + 1, &select_fds, NULL, NULL, &select_timeout);
2295 if (rc < 0 && errno != EINTR)
2297 perror("select failed in FileMoveCopy");
2302 /* call FileOpPipeCB to read & process the data from the pipe */
2303 FileOpPipeCB((XtPointer)cb_data, &fd, NULL);
2304 DPRINTF(("FileMoveCopy: FileOpPipeCB -> fd = %d\n", fd));
2307 * If the background process is done, FileOpPipeCB sets fd
2308 * to zero (in case of success) or -1 (in case of failure).
2312 operation_done = (fd == 0);
2318 return operation_done;
2322 /*--------------------------------------------------------------------
2323 * FileMoveCopy, FileMoveCopyDesktop
2324 * External entry points for invoking _FileMoveCopy
2325 *------------------------------------------------------------------*/
2329 FileMgrData *file_mgr_data,
2336 unsigned int modifiers,
2337 void (*finish_callback)(),
2338 XtPointer callback_data)
2340 return _FileMoveCopy( (XtPointer)file_mgr_data, to_file, directory, host,
2341 host_set, file_set, NULL, file_count, modifiers, NULL,
2342 finish_callback, callback_data);
2347 FileMoveCopyDesktop(
2348 FileViewData *file_view_data,
2353 unsigned int modifiers,
2354 DesktopRec *desktopWindow,
2355 void (*finish_callback)(),
2356 XtPointer callback_data)
2358 return _FileMoveCopy ((XtPointer)file_view_data,
2373 /*====================================================================
2376 * Run a background process to rename an object.
2378 *==================================================================*/
2380 /*--------------------------------------------------------------------
2381 * ChangeIconNameProcess:
2382 * Main routine of the background process
2383 *------------------------------------------------------------------*/
2386 ChangeIconNameProcess(
2389 char *directory_name,
2393 char * full_name, * old_full_name, *dir_path;
2394 struct stat stat_buf;
2399 Tt_status tt_status;
2401 /* Check for uniqueness */
2402 full_name = ResolveLocalPathName(host_name, directory_name, new_name, home_host_name, &tt_status);
2403 if ( TT_OK != tt_status )
2405 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2406 pipe_msg = PIPEMSG_FILEOP_ERROR;
2407 write(pipe_fd, &pipe_msg, sizeof(short));
2412 if (lstat(full_name, &stat_buf) == 0)
2414 /* Name is not unique */
2415 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2416 pipe_msg = PIPEMSG_EXIST_ERROR;
2417 write(pipe_fd, &pipe_msg, sizeof(short));
2424 /* send a modified message back through the pipe */
2426 dir_path = ResolveLocalPathName(host_name, directory_name, NULL, home_host_name, &tt_status);
2427 if( TT_OK != tt_status )
2429 DPRINTF(("ChadengeIconNameProcess: sending exist error\n"));
2430 pipe_msg = PIPEMSG_FILEOP_ERROR;
2431 write(pipe_fd, &pipe_msg, sizeof(short));
2437 if (stat(dir_path, &stat_buf) == 0)
2438 modify_time = stat_buf.st_mtime;
2441 /* rename the file */
2442 old_full_name = ResolveLocalPathName(host_name, directory_name, old_name, home_host_name, &tt_status);
2443 if( TT_OK != tt_status )
2445 DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2446 pipe_msg = PIPEMSG_FILEOP_ERROR;
2447 write(pipe_fd, &pipe_msg, sizeof(short));
2452 success = FileManip((Widget) (intptr_t) pipe_fd, MOVE_FILE, old_full_name, full_name, TRUE,
2453 FileOpError, True, NOT_DESKTOP);
2454 XtFree( old_full_name );
2455 /* send a 'done' msg through the pipe */
2456 rc = success? 0: -1;
2459 pipe_msg = PIPEMSG_FILE_MODIFIED;
2460 write(pipe_fd, &pipe_msg, sizeof(short));
2461 write(pipe_fd, &modify_time, sizeof(long));
2463 DPRINTF(("ChangeIconNameProcess: sending DONE, rc %d\n", rc));
2464 pipe_msg = PIPEMSG_DONE;
2465 write(pipe_fd, &pipe_msg, sizeof(short));
2466 write(pipe_fd, &rc, sizeof(int));
2468 PipeWriteString(pipe_fd, full_name);
2469 XtFree( full_name );
2474 /*--------------------------------------------------------------------
2476 * Read and process data sent through the pipe.
2477 *------------------------------------------------------------------*/
2481 XtPointer client_data,
2485 ChangeIconCBData *cb_data = (ChangeIconCBData *)client_data;
2486 FileViewData *file_view_data = cb_data->file_view_data;
2487 DesktopRec *desktopWindow = cb_data->desktopWindow;
2490 DirectorySet *directory_set;
2491 FileMgrData *file_mgr_data = NULL;
2492 FileMgrRec *file_mgr_rec;
2496 char *title, *err_msg, *err_arg;
2502 Boolean desktop_changed;
2504 /* get widget for error messages */
2505 if (cb_data->desktop)
2507 msg_widget = XtParent(cb_data->w);
2511 directory_set = (DirectorySet *)file_view_data->directory_set;
2512 file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
2513 file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
2514 msg_widget = file_mgr_rec->file_window;
2517 /* read the msg from the pipe */
2519 n = PipeRead(*fd, &pipe_msg, sizeof(short));
2520 DPRINTF(("ChangeIconPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
2522 if (pipe_msg == PIPEMSG_FILE_MODIFIED)
2524 /* get modify time */
2525 PipeRead(*fd, &modify_time, sizeof(long));
2527 /* mark the old & new files as modified in the directory cache */
2528 if (modify_time != 0)
2529 DirectoryModifyTime(cb_data->host_name, cb_data->directory_name,
2531 DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
2533 DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
2538 if (pipe_msg == PIPEMSG_EXIST_ERROR)
2540 /* Name is not unique */
2541 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2542 if (cb_data->desktop)
2544 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.");
2545 err_msg = XtNewString(tmpStr);
2548 err_msg = XtNewString(GETMESSAGE(9,9, "A file with this name already exists.\nPlease choose a different name."));
2550 _DtMessage (msg_widget, title, err_msg, NULL, HelpRequestCB);
2555 else if (pipe_msg == PIPEMSG_FILEOP_ERROR)
2557 /* the rename failed */
2558 PipeRead(*fd, &rc, sizeof(int));
2559 err_msg = PipeReadString(*fd);
2560 err_arg = PipeReadString(*fd);
2561 FileOperationError(msg_widget, err_msg, err_arg);
2566 else if (pipe_msg == PIPEMSG_DONE)
2568 /* get the return code */
2569 PipeRead(*fd, &rc, sizeof(int));
2572 /* the rename was successful */
2573 full_name = PipeReadString(*fd);
2575 /* All went well, destroy the text field */
2576 XtUnmanageChild(cb_data->w);
2577 XtDestroyWidget(cb_data->w);
2579 /* Force the icon label to be updated immediately */
2580 if (cb_data->desktop)
2582 XmProcessTraversal(desktopWindow->iconGadget, XmTRAVERSE_CURRENT);
2583 desktopWindow->text = NULL;
2584 /* we'll catch this icon label in the loop after the else */
2588 file_mgr_data->renaming = NULL;
2590 label = XmStringCreateLocalized(cb_data->new_name);
2591 XtSetArg(args[0], XmNstring, label);
2592 XtSetValues(file_view_data->widget, args, 1);
2593 XmStringFree(label);
2594 XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
2595 XmUpdateDisplay (file_mgr_rec->file_window);
2598 * To prevent the positional data from becoming disassociated with
2599 * this file, we need to change the name in the positional data
2602 for (i = 0; i < file_mgr_data->num_objects; i++)
2604 if (strcmp(cb_data->old_name,
2605 file_mgr_data->object_positions[i]->name) == 0)
2608 XtFree(file_mgr_data->object_positions[i]->name);
2609 file_mgr_data->object_positions[i]->name =
2610 XtNewString(cb_data->new_name);
2617 * Check all desktop windows to see if they were linked to
2618 * the file we just renamed. If so, we need to change the
2619 * link in .dt/Desktop that points to it.
2621 * Note: We could do this in a background process, but we assume
2622 * that .dt/Desktop is local or, if it's remote and the remote server
2623 * is down, the user is screwed anyway. So we assume it's ok to do
2624 * blocking operations on .dt/Desktop in the main process.
2625 * Hence we go for the simpler solution here.
2627 desktop_changed = False;
2628 for (i = 0; i < desktop_data->numIconsUsed; i++)
2630 desktopWindow = desktop_data->desktopWindows[i];
2632 if (strcmp(cb_data->host_name, desktopWindow->host) == 0 &&
2633 strcmp(cb_data->directory_name, desktopWindow->dir_linked_to) == 0
2634 && strcmp(cb_data->old_name, desktopWindow->file_name) == 0)
2638 /* Force the icon label to be updated immediately */
2639 label = XmStringCreateLocalized(cb_data->new_name);
2640 XtSetArg(args[0], XmNstring, label);
2641 XtSetValues(desktopWindow->iconGadget, args, 1);
2642 XmStringFree(label);
2644 XtFree(desktopWindow->file_name);
2645 desktopWindow->file_name = XtNewString(cb_data->new_name);
2647 XtFree(desktopWindow->file_view_data->file_data->file_name);
2648 desktopWindow->file_view_data->file_data->file_name =
2649 XtNewString(cb_data->new_name);
2650 if( strcmp( desktopWindow->title, cb_data->old_name ) == 0 )
2652 XtFree( desktopWindow->title );
2653 desktopWindow->title = XtNewString( cb_data->new_name );
2656 GenerateShape(desktopWindow);
2658 RegisterIconDropsDT(desktopWindow);
2659 XmUpdateDisplay (desktopWindow->iconGadget);
2661 desktop_changed = True;
2665 if (desktop_changed)
2667 SaveDesktopInfo(NORMAL_RESTORE);
2675 fprintf(stderr, "Internal error in ChangeIconPipeCB: bad pipe_msg %d\n",
2678 /* arrange for the modified directory to be updated */
2679 DirectoryEndModify(cb_data->host_name, cb_data->directory_name);
2681 /* close the pipe and cancel the callback */
2685 /* free callback data */
2686 XtFree(cb_data->host_name);
2687 XtFree(cb_data->directory_name);
2688 XtFree(cb_data->old_name);
2689 XtFree(cb_data->new_name);
2690 XtFree((char *)cb_data);
2694 /*--------------------------------------------------------------------
2696 * Start the background process and set up callback for the pipe.
2697 *------------------------------------------------------------------*/
2703 FileViewData *file_view_data,
2704 DesktopRec *desktopWindow,
2706 char *directory_name)
2708 static char *pname = "_ChangeIconName";
2709 ChangeIconCBData *cb_data;
2721 int dirNameLength = strlen (directory_name);
2722 int maxFileNameLength = pathconf (directory_name, _PC_NAME_MAX);
2726 /* get the new name */
2727 XtSetArg(args[0], XmNvalue, &input_name);
2728 XtSetArg(args[1], XmNuserData, &old_name);
2729 XtGetValues(w, args, 2);
2731 new_name = (char *)_DtStripSpaces(XtNewString(input_name));
2732 length = strlen (new_name);
2735 /* new name must be a simple name, no path */
2737 if (DtStrchr (new_name, '/') != NULL)
2738 msg = XtNewString(GetSharedMessage(LOCAL_RENAME_ONLY_ERROR));
2739 #ifdef _CHECK_FOR_SPACES
2740 else if (DtStrchr (new_name, ' ') != NULL ||
2741 DtStrchr (new_name, '\t') != NULL)
2743 msg = XtNewString(GetSharedMessage(NO_SPACES_ALLOWED_ERROR));
2746 else if (length == 0 || strcmp(new_name, old_name) == 0)
2748 /* Noop; simply remove the text field */
2749 XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
2753 UnpostDTTextField();
2757 DirectorySet *directory_set =
2758 (DirectorySet *)file_view_data->directory_set;
2759 FileMgrData *file_mgr_data =
2760 (FileMgrData *)directory_set->file_mgr_data;
2761 FileMgrRec *file_mgr_rec =
2762 (FileMgrRec *)file_mgr_data->file_mgr_rec;
2763 file_mgr_rec->menuStates |= RENAME;
2764 UnpostTextField( file_mgr_data );
2765 file_mgr_data->renaming = NULL;
2769 /* Ensure the new name has length less than or equal to the maximum
2770 length that the system allows.
2771 If maxFileNameLength == -1 the file system is not supporting POSIX, use MAXNAMLEN
2773 else if( maxFileNameLength < -1 || ( maxFileNameLength == -1 && ( length > MAXNAMLEN || length + dirNameLength > MAX_PATH ) ) || ( maxFileNameLength > 0 && length > maxFileNameLength ) )
2775 msg = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2781 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2782 _DtMessage (XtParent (w), title, msg, NULL, HelpRequestCB);
2789 /* Check to see if the file has a representitive on the Desktop. */
2790 if (desktopWindow == NULL)
2792 for (i = 0; i < desktop_data->numIconsUsed; i++)
2794 if (strcmp(host_name,
2795 desktop_data->desktopWindows[i]->host) == 0 &&
2796 strcmp(directory_name,
2797 desktop_data->desktopWindows[i]->dir_linked_to) == 0 &&
2798 strcmp(old_name, desktop_data->desktopWindows[i]->
2799 file_view_data->file_data->file_name) == 0)
2801 desktopWindow = desktop_data->desktopWindows[i];
2807 if (desktopWindow != NULL)
2810 * There is a representation of this file on the desktop:
2811 * check if the there are any objects which match the new_name
2813 for (j = 0; j < desktop_data->numIconsUsed; j++)
2815 if (strcmp(new_name, desktop_data->desktopWindows[j]->
2816 file_view_data->file_data->file_name) == 0)
2818 title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2820 tmpStr = GETMESSAGE(28,9, "An object with this name already exists on the Workspace.\nPlease choose a different name.");
2822 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.");
2823 msg = XtNewString(tmpStr);
2824 _DtMessage(XtParent (w), title, msg, NULL, HelpRequestCB);
2834 * Now we are ready to start the background process
2835 * that does the actual rename.
2838 /* set up callback data */
2839 cb_data = XtNew(ChangeIconCBData);
2841 cb_data->desktop = desktop;
2842 cb_data->file_view_data = file_view_data;
2843 cb_data->desktopWindow = desktopWindow;
2844 cb_data->host_name = XtNewString(host_name);
2845 cb_data->directory_name = XtNewString(directory_name);
2846 cb_data->old_name = XtNewString(old_name);
2847 cb_data->new_name = new_name;
2849 /* mark the directory as being modified in the directory cache */
2850 DirectoryBeginModify(host_name, directory_name);
2855 /* fork the process that does the actual work */
2859 DirectoryAbortModify(host_name, directory_name);
2861 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
2862 pname, getppid(), getpid(), errno, strerror(errno));
2868 DBGFORK(("%s: child forked, pipe %d\n", pname, pipe_fd[1]));
2870 close(pipe_fd[0]); /* child won't read from the pipe */
2872 rc = ChangeIconNameProcess(pipe_fd[1], host_name, directory_name,
2873 old_name, new_name);
2876 DBGFORK(("%s: child exiting\n", pname));
2881 DBGFORK(("%s: forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
2884 /* parent: set up callback to get the pipe data */
2885 close(pipe_fd[1]); /* parent won't write the pipe */
2887 cb_data->child = pid;
2889 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
2890 pipe_fd[0], (XtPointer)XtInputReadMask,
2891 ChangeIconPipeCB, (XtPointer)cb_data);
2898 XtPointer client_data,
2899 XmTextVerifyCallbackStruct * call_data)
2901 int value, size, increment, page;
2903 FileMgrData *file_mgr_data = (FileMgrData *)client_data;
2904 FileMgrRec *file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
2905 DirectorySet *directory_set = (DirectorySet *)(file_mgr_data->renaming->directory_set);
2907 if (call_data->reason == XmCR_MODIFYING_TEXT_VALUE ||
2908 call_data->reason == XmCR_MOVING_INSERT_CURSOR )
2911 /* x1 - x value of the text widget with respect to scroll window
2912 x2,y2 - x,y values of the cursor position (new) w.r.t text widget
2913 x3,y3 - x,y values of the cursor position (previous) w.r.t textW
2915 Position x1,x2,y2,x3,y3;
2916 /* width of the text widget */
2917 Dimension stringWidth;
2919 XtSetArg(args[0],XmNx,&x1);
2920 XtGetValues(w,args,1);
2922 if(XtIsManaged(file_mgr_rec->vertical_scroll_bar))
2923 SWwidth=(file_mgr_rec->scroll_window->core.width -
2924 file_mgr_rec->vertical_scroll_bar->core.width);
2926 SWwidth=file_mgr_rec->scroll_window->core.width;
2928 XmTextFieldPosToXY(w,call_data->newInsert,&x2,&y2);
2929 XmTextFieldPosToXY(w,call_data->currInsert,&x3,&y3);
2931 XtSetArg(args[0],XmNwidth,&stringWidth);
2932 XtGetValues(w,args,1);
2934 printf("\n x2=%d x1=%d x3=%d\n",x2,x1,x3);
2936 if ( (Dimension)(call_data->newInsert) < stringWidth )
2938 if( XtIsManaged(file_mgr_rec->horizontal_scroll_bar) )
2940 XmScrollBarGetValues( file_mgr_rec->horizontal_scroll_bar,
2941 &value, &size, &increment, &page);
2943 printf("\n value = %d",value);
2945 /* case where cursor is moved forward */
2949 XtSetArg (args[0], XmNmaximum, &max);
2950 XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
2951 if( (value < (max-size)) &&
2952 ((x1+x2) - value > 0 ) &&
2953 ( (Position)(((x1+x2) - value) +
2954 file_mgr_rec->vertical_scroll_bar->core.width) > (Position) SWwidth ) )
2956 if( (value+(x2-x3)) > (max-size) )
2960 XmScrollBarSetValues(
2961 file_mgr_rec->horizontal_scroll_bar,
2962 value, size, increment, page,True
2966 /* case where cursor is moved in reverse direction */
2967 else if( (x2-x3) < 0 )
2970 XtSetArg (args[0], XmNminimum, &min);
2971 XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
2972 if( (value > min) && ((Position)(x1+x3) < (Position)(value+
2973 file_mgr_rec->vertical_scroll_bar->core.width)) )
2975 if( (x2 <= 0) || ((value - (x3-x2)) < min) )
2979 XmScrollBarSetValues(file_mgr_rec->horizontal_scroll_bar,
2980 value, size, increment, page,True
2988 _ChangeIconName (w, False, file_mgr_data->renaming, NULL,
2989 file_mgr_data->host, directory_set->name);
2996 XtPointer client_data,
2997 XtPointer call_data)
2999 DesktopRec * desktopWindow = (DesktopRec *)client_data;
3001 _ChangeIconName (w, True, desktopWindow->file_view_data, desktopWindow,
3002 desktopWindow->host, desktopWindow->dir_linked_to);
3006 /*====================================================================
3009 * Run a background process to create a file or directory.
3011 *==================================================================*/
3013 /*--------------------------------------------------------------------
3015 * Build a host, directory, and file name path to be used as the
3016 * destination of a create, copy or move operation.
3017 *------------------------------------------------------------------*/
3030 strcpy(to_host, from_host);
3032 if (strncmp (new_name, "/", 1) == 0)
3034 strcpy(to_dir, new_name);
3038 if (strcmp(to_dir, "/") == 0)
3039 sprintf(to_dir, "%s%s", from_dir, new_name);
3041 sprintf(to_dir, "%s/%s", from_dir, new_name);
3044 ptr = strrchr(to_dir, '/');
3046 strcpy(to_file, ptr + 1);
3050 /*--------------------------------------------------------------------
3052 * Main routine of background process for MakeFile
3053 *------------------------------------------------------------------*/
3064 struct stat stat_buf;
3070 Tt_status tt_status;
3072 /* assume success */
3075 /* get the full name of the file/dir to be created */
3076 to = ResolveLocalPathName(to_host, to_dir, to_file, home_host_name, &tt_status);
3080 /* check if a file/dir with the same name already exists */
3081 else if (lstat (to, &stat_buf) == 0)
3084 /* now create the file/dir */
3087 /* send a modified message back through the pipe */
3089 dir_path = ResolveLocalPathName(to_host, to_dir, NULL, home_host_name, &tt_status);
3090 if (stat(dir_path, &stat_buf) == 0)
3091 modify_time = stat_buf.st_mtime;
3094 pipe_msg = PIPEMSG_FILE_MODIFIED;
3095 write(pipe_fd, &pipe_msg, sizeof(short));
3096 write(pipe_fd, &modify_time, sizeof(long));
3099 if (type == DtDIRECTORY)
3101 if (mkdir (to, (int) DtFILE_DIR_CREATION_MASK) != 0)
3109 mode = DtFILE_DATA_CREATION_MASK;
3111 mode = DtFILE_OTHER_CREATION_MASK;
3113 if ((fnew = creat(to, (int) mode)) < 0)
3120 /* send a 'done' msg through the pipe */
3121 pipe_msg = PIPEMSG_DONE;
3122 DPRINTF(("MakeFileProcess: sending DONE, rc %d\n", rc));
3123 write(pipe_fd, &pipe_msg, sizeof(short));
3124 write(pipe_fd, &rc, sizeof(int));
3125 PipeWriteString(pipe_fd, to);
3133 /*--------------------------------------------------------------------
3135 * Read and process data sent through the pipe.
3136 *------------------------------------------------------------------*/
3140 XtPointer client_data,
3144 MakeFileCBData *cb_data = (MakeFileCBData *)client_data;
3151 /* read the msg from the pipe */
3153 n = PipeRead(*fd, &pipe_msg, sizeof(short));
3155 if (pipe_msg == PIPEMSG_FILE_MODIFIED)
3157 /* get modify time */
3158 PipeRead(*fd, &modify_time, sizeof(long));
3160 /* mark the file updated in the directory cache */
3161 if (modify_time != 0)
3162 DirectoryModifyTime(cb_data->to_host, cb_data->to_dir, modify_time);
3163 DirectoryFileModified(cb_data->to_host, cb_data->to_dir,
3168 if (pipe_msg == PIPEMSG_DONE)
3170 PipeRead(*fd, &rc, sizeof(int));
3171 full_name = PipeReadString(*fd);
3175 fprintf(stderr, "Internal error in MakeFilePipeCB: bad pipe_msg %d\n",
3181 DPRINTF(("MakeFilePipeCB: n %d, pipe_msg %d, rc %d\n", n, pipe_msg, rc));
3183 /* arrange for the modified directory to be updated */
3184 DirectoryEndModify(cb_data->to_host, cb_data->to_dir);
3186 /* close the pipe and cancel the callback */
3190 /* Store away the newly created file so we later on we can
3194 MakeFileDoneData * data = (MakeFileDoneData *)cb_data->callback_data;
3195 DialogCallbackStruct * call_struct = data->call_struct;
3196 FileMgrData * file_mgr_data = call_struct->file_mgr_data;
3198 file_mgr_data->scrollToThisDirectory = cb_data->to_dir;
3199 file_mgr_data->scrollToThisFile = cb_data->to_file;
3202 /* call the callback routine */
3203 if (cb_data->finish_callback)
3204 (*cb_data->finish_callback)(cb_data->callback_data, full_name, rc);
3206 /* free callback data */
3208 XtFree(cb_data->to_host);
3210 /* Don't free to_dir and to_file. We used this to remember
3211 which file so later on we can scroll to it.
3212 XtFree(cb_data->to_dir);
3213 XtFree(cb_data->to_file);
3216 XtFree((char *)cb_data);
3220 /*--------------------------------------------------------------------
3222 * Start the background process and set up callback for the pipe.
3223 *------------------------------------------------------------------*/
3229 char *directory_name,
3232 void (*finish_callback)(),
3233 XtPointer callback_data)
3235 static char *pname = "MakeFile";
3236 MakeFileCBData *cb_data;
3237 char to_host[MAX_PATH];
3238 char to_dir[MAX_PATH];
3239 char to_file[MAX_PATH];
3244 /* get host & path of the target file */
3245 GetTarget(host_name, directory_name, new_name, to_host, to_dir, to_file);
3247 /* mark the target directory as being modified in the directory cache */
3248 DirectoryBeginModify(to_host, to_dir);
3250 /* parent: set up callback to get the pipe data */
3251 cb_data = XtNew(MakeFileCBData);
3252 cb_data->to_host = XtNewString(to_host);
3253 cb_data->to_dir = XtNewString(to_dir);
3254 cb_data->to_file = XtNewString(to_file);
3255 cb_data->finish_callback = finish_callback;
3256 cb_data->callback_data = callback_data;
3261 /* fork the process that does the actual work */
3265 DirectoryAbortModify(to_host, to_dir);
3267 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
3268 pname, getppid(), getpid(), errno, strerror(errno));
3275 DBGFORK(("%s: child forked, pipe %d\n", pname, pipe_fd[1]));
3277 close(pipe_fd[0]); /* child won't read from the pipe */
3279 rc = MakeFileProcess(pipe_fd[1], to_host, to_dir, to_file, type);
3282 DBGFORK(("%s: child exiting\n", pname));
3287 DBGFORK(("%s: forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
3289 /* parent: set up callback to get the pipe data */
3290 close(pipe_fd[1]); /* parent won't write the pipe */
3292 cb_data->child = pid;
3294 XtAppAddInput(XtWidgetToApplicationContext(toplevel),
3295 pipe_fd[0], (XtPointer)XtInputReadMask,
3296 MakeFilePipeCB, (XtPointer)cb_data);
3300 /*=============================================================
3302 * The following routines handle the creation of files from
3303 * buffers: MakeFilesFromBuffers and MakeFilesFromBuffersDT
3306 *=============================================================*/
3309 MakeFilesFromBuffers(
3310 FileMgrData *file_mgr_data,
3315 BufferInfo *buffer_set,
3317 void (*finish_callback)(),
3318 XtPointer callback_data)
3320 return _FileMoveCopy ((XtPointer)file_mgr_data, NULL, directory, host,
3321 host_set, file_set, buffer_set, num_of_buffers,
3322 0, NULL, finish_callback, callback_data);
3327 MakeFilesFromBuffersDT(
3328 FileViewData *file_view_data,
3332 BufferInfo *buffer_set,
3334 DesktopRec *desktopWindow,
3335 void (*finish_callback)(),
3336 XtPointer callback_data)
3338 return _FileMoveCopy ((XtPointer)file_view_data, NULL, directory,
3340 host_set, file_set, buffer_set, num_of_buffers,
3341 0, desktopWindow, finish_callback, callback_data);
3345 /*====================================================================
3347 * CreateFileFromBuffer
3348 * Routine to create a file from a buffer
3350 *==================================================================*/
3354 CreateFileFromBuffer(int pipe_s2m,
3356 char *fully_qualified_name,
3363 Boolean BufferIsExecutable=FALSE;
3364 char *err_msg, *err_arg, *tmpStr;
3365 char *format_str, *strerror_str;
3366 int format_param_len=20;
3372 /* Set the permissions depending if buffer is a */
3373 /* file or an execuatable */
3374 if (_DtIsBufferExecutable(buffer,size))
3376 mode = S_IRUSR | S_IWUSR | S_IXUSR |
3377 S_IRGRP | S_IWGRP | S_IXGRP |
3378 S_IROTH | S_IWOTH | S_IXOTH;
3382 mode = S_IRUSR | S_IWUSR |
3387 /* Create the target file */
3388 if ((fnew = open(fully_qualified_name, O_CREAT| O_WRONLY, mode)) < 0)
3390 DPRINTF(("CreateBufferFromFile: Could not create %s\n",
3391 fully_qualified_name));
3397 /* Write the buffer to the target file */
3398 if ((rc = write(fnew, buffer, size)) < 0 )
3400 DPRINTF (("CreateBufferFromFile: Could not write buffer to %s\n",
3401 fully_qualified_name));
3408 DPRINTF (("CreateBuffeFromFile: Target file %s created\n",
3409 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 = NULL,*err_msg = NULL,*title = NULL,*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");
3525 msgptr = XtCalloc(1,strlen(err_msg)+strlen(cb_data->updates[index].file)+10);
3526 sprintf(msgptr,err_msg,cb_data->updates[index].file);
3528 if(cb_data->callback_data)
3529 dialogwidget = ((RenameDoneData *)(cb_data->callback_data))->w;
3531 dialogwidget = toplevel;
3532 _DtMessage (dialogwidget,title, msgptr, NULL, HelpRequestCB);
3539 /*==============================================================
3541 * appendErrorMessage
3543 * if "arg" is not null, "new" is assumed to include %s
3544 * "message" is re-allocated and so will have a different
3545 * address than when the function was called
3547 * usage: errorMsg = appendErrorMessage(errorMsg,errStr,file);
3549 *==============================================================
3553 appendErrorMessage(String message, String new, String arg)
3558 newMessage = XtNewString(new);
3561 newMessage = XtMalloc(strlen(new) + strlen(arg) + 1);
3562 sprintf(newMessage,new,arg);
3565 if (message == NULL)
3567 message = XtRealloc(message, (strlen(newMessage) + 2));
3571 message = XtRealloc(message, (strlen(message) + strlen(newMessage) + 2));
3573 strcat(message,newMessage);
3574 strcat(message,"\n");
3580 } /* end appendErrorMessage */
3583 DisplayErrorMessage(
3591 localstr = (char *) XtMalloc(strlen(errMsg)+strlen(from)+strlen(tdir) + 10 );
3592 sprintf(localstr,errMsg,tdir,from);
3593 PipeWriteErrmsg(pipe_s2m, -1, localstr, NULL);
3601 char filename [MAX_PATH];
3603 int slen = strlen(source_path);
3605 if(slen > strlen(dest_path))
3607 strcpy (filename, dest_path);
3608 cptr = strchr(&filename[slen-1],'/');
3611 return ((strcmp(source_path,filename) == 0)?True:False);