Spelling fixes
[oweals/cde.git] / cde / programs / dtfile / FileManip.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* $TOG: FileManip.c /main/10 1999/12/09 13:06:10 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           FileManip.c
28  *
29  *   COMPONENT_NAME: Desktop File Manager (dtfile)
30  *
31  *   Description:    This module does the copy, move and rename commands.
32  *                   Included are functions to control command execution,
33  *                   move a directory, get the directory portion of a pathname,
34  *                   get the file name portion of a pathname, and check if a
35  *                   folder is to be moved within itself.
36  *
37  *   FUNCTIONS: Check
38  *              CheckAccess
39  *              CopyDir
40  *              DName
41  *              FileManip
42  *              FileOperationError
43  *              MoveDir
44  *              defined
45  *
46  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
47  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
48  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
49  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
50  *
51  ****************************************************************************
52  ************************************<+>*************************************/
53
54 #if defined(SVR4)
55 #    include <sys/fs/ufs_fs.h>
56 #    define ROOTINO UFSROOTINO
57 #else
58 #  if defined(__linux__) || defined(CSRG_BASED)
59 #    define ROOTINO 2
60 #  endif
61 #  include <sys/param.h>
62 #endif  /* SVR4 */
63
64 #include <sys/types.h>
65
66 #include <sys/stat.h>
67 #include <stdio.h>
68 #include <signal.h>
69 #include <errno.h>
70 #include <fcntl.h>
71
72 /** The following ifdefs need to be straightened out
73  ** They are a mess.
74  **/
75 #ifdef sun
76 #include <unistd.h>
77 #include <limits.h>
78 #ifndef SVR4
79 #include <ufs/fs.h>
80 #endif
81 #else
82 #ifdef __ultrix
83 #include <unistd.h>
84 #include <limits.h>
85 #include <ufs/fs.h>
86 #else
87 #include <unistd.h>
88 #include <limits.h>
89 #ifdef __hpux
90 #include <unistd.h>
91 #endif
92 #endif /* __ultrix */
93 #endif /* sun */
94
95 #include <Xm/Xm.h>
96
97 #include <Xm/MwmUtil.h>
98
99 #include <Dt/DtP.h>                     /* required for DtDirPaths type */
100 #include <Dt/Connect.h>
101 #include <Dt/DtNlUtils.h>
102 #include <Dt/SharedProcs.h>
103
104 #include "Encaps.h"
105 #include "SharedProcs.h"
106 #include "FileMgr.h"
107 #include "Desktop.h"
108 #include "Main.h"
109 #include "Help.h"
110 #include "SharedMsgs.h"
111
112 #ifndef CDE_INSTALLATION_TOP
113 #define CDE_INSTALLATION_TOP "/usr/dt"
114 #endif
115
116 /*  Local Function Definitions  */
117 static char * MOVE_CMD = "/bin/mv";
118 static char * LINK_CMD = "/bin/ln";
119 static char * REMOVE_CMD = "/bin/rm";
120 static char * DTCOPY = CDE_INSTALLATION_TOP "/bin/dtfile_copy";
121
122
123 /************************************************************************
124  *
125  *  CheckAccess
126  *
127  ************************************************************************/
128 int
129 CheckAccess(
130         char *fname,
131         int what)
132 {
133     int access_priv;
134     uid_t save_ruid;
135     gid_t save_rgid;
136
137 #if defined(__ultrix)
138 /*--------------------------------------------------------------------
139  * access code for __ultrix
140  *------------------------------------------------------------------*/
141
142       setreuid(geteuid(),-1);
143       return access (fname, what);
144
145 #else
146 #ifdef BLS
147 /*--------------------------------------------------------------------
148  * access code for BLS
149  *------------------------------------------------------------------*/
150
151       setresuid(geteuid(),-1,-1);
152       return access (fname, what);
153
154 #else /* the rest of the OS's */
155
156    save_ruid = getuid();
157
158 #ifdef _AIX
159    setreuid(geteuid(),-1);
160 #else
161    setuid(geteuid());
162 #endif /* _AIX */
163
164    save_rgid = getgid();
165
166 #ifdef _AIX
167    setregid(getegid(),-1);
168 #else
169    setgid(getegid());
170 #endif /* _AIX */
171
172    access_priv = access (fname, what);
173
174 #ifdef _AIX
175    setreuid(save_ruid,-1);
176    setregid(save_rgid,-1);
177 #else
178    setuid(save_ruid);
179    setgid(save_rgid);
180 #endif /* _AIX */
181
182    return access_priv;
183 #endif /* BLS */
184 #endif /* Apollo */
185 }
186
187
188 /************************************************************************
189  *
190  *  FileOperationError
191  *      Display an error message.
192  *
193  ************************************************************************/
194 void
195 FileOperationError(
196         Widget w,
197         char *message1,
198         char *message2 )
199 {
200    char *message_buf;
201    char * title;
202    char * tmpStr;
203
204   if (message2 != NULL)
205    {
206      message_buf = XtMalloc(strlen(message1) + strlen(message2) + 1);
207      (void) sprintf(message_buf,message1, message2);
208    }
209    else
210    {
211      message_buf = XtMalloc(strlen(message1) + 1);
212      (void) sprintf(message_buf, "%s", message1);
213    }
214
215    /*  Display an error dialog  */
216    tmpStr = GetSharedMessage(FILE_MANIPULATION_ERROR_TITLE);
217    title = XtNewString(tmpStr);
218    _DtMessage (w, title, message_buf, NULL, HelpRequestCB);
219    XtFree(title);
220    XtFree(message_buf);
221 }
222
223
224 /************************************************************************
225  *
226  *  DName
227  *      Returns the file name of its argument.
228  *      Keep looking thru the string until a "/" is found which still
229  *      has some characters after it.
230  *
231  ************************************************************************/
232 char *
233 DName(
234         register char *name )
235 {
236    char * p;
237    char * q;
238
239    p = q = name;
240
241    while (1)
242    {
243       q = DtStrchr(q, '/');
244       if ((q) && *(q+1))
245          p = q + 1;
246
247       if (q == NULL)
248          break;
249
250       q++;
251    }
252
253    return(p);
254 }
255
256
257 /************************************************************************
258  *
259  *  Check
260  *
261  ************************************************************************/
262 static int
263 Check(
264         Widget w,
265         register char *spth,
266         register ino_t dinode,
267         int mode,
268         void (*errorHandler)() )
269 {
270    struct stat sbuf;
271    char filename [MAX_PATH];
272    char * msg;
273    char * tmpStr;
274
275    sbuf.st_ino = 0;
276
277    (void) strcpy (filename, spth);
278
279    while (sbuf.st_ino != ROOTINO)
280    {
281       if (lstat (filename, &sbuf) < 0)
282       {
283          if (errorHandler)
284          {
285             tmpStr = (GETMESSAGE(11,33, "Cannot open %s"));
286             msg = XtNewString(tmpStr);
287             (*errorHandler) (w, msg, filename);
288             XtFree(msg);
289          }
290          return (False);
291       }
292
293       if (sbuf.st_ino == dinode)
294       {
295          if (errorHandler)
296          {
297             if (mode == COPY_FILE)
298               tmpStr = GETMESSAGE(11,35, "Cannot copy a folder into itself.");
299             else
300               tmpStr = GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s");
301             msg = XtNewString(tmpStr);
302             if (mode == COPY_FILE)
303               (*errorHandler) (w, msg, NULL);
304             else
305               (*errorHandler) (w, msg, filename);
306             XtFree(msg);
307          }
308          return(1);
309       }
310
311       (void) strcat (filename, "/..");
312    }
313
314    return(0);
315 }
316
317
318 /************************************************************************
319  *
320  *  MoveDir
321  *
322  ************************************************************************/
323
324 static Boolean
325 MoveDir(
326         Widget w,
327         register char *source,
328         register char *target,
329         struct stat *sourceStatInfo,
330         void (*errorHandler)(),
331         char ** targetRtn ,
332         int type )
333 {
334    static char *pname = "MoveDir";
335    register char *p;
336
337    char * targetDir;            /* original target dir path */
338    char *link_path;
339    int link_result;
340
341    struct stat  s1;             /* status of from file */
342    struct stat  s2;             /* status of to file   */
343    char * cptr;
344    int len, val, val1;
345
346    static char buf [BUF_SIZE];  /* generic buffer */
347    char filename [MAX_PATH];    /* buffer to hold the full file name */
348    char * msg;
349    char * tmpStr;
350    int child_pid, rc;
351
352    /* Copy target so we have it for an error dialog if we need it */
353    targetDir = XtNewString(target);
354    *targetRtn = NULL;
355
356    if ((val = stat (target, &s2)) < 0)
357       val = lstat(target, &s2);
358
359    /* Check if move to itself */
360    if( sourceStatInfo->st_dev == s2.st_dev)
361    {
362      if (Check (w, target, sourceStatInfo->st_ino, MOVE_FILE, NULL ))
363        return (False);
364    }
365
366    if (val >= 0) /* target exists */
367    {
368       if ((s2.st_mode & S_IFMT) != S_IFDIR) /* target not directory */
369       {
370          if (errorHandler)
371          {
372             char * tmpStr;
373             tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
374             msg = XtNewString(tmpStr);
375             (*errorHandler) (w, msg, target);
376             XtFree(msg);
377          }
378          XtFree(targetDir);
379          return (False);
380       }
381
382       (void) strcpy (buf, target);
383       target = buf;
384       *targetRtn = buf;
385
386       DtLastChar(buf, &cptr, &len);
387       if ((len != 1) || (*cptr != '/'))
388          (void) strcat (buf, "/");
389       (void) strcat (buf, DName (source));
390
391       if (lstat (target, &s2) >= 0) /* new target exists */
392       {
393          if (errorHandler)
394          {
395             char * tmpStr;
396
397             tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
398             msg = XtNewString(tmpStr);
399             (*errorHandler) (w, msg, target);
400             XtFree(msg);
401          }
402          XtFree(targetDir);
403          return (False);
404       }
405    }
406
407
408    p = DName (source);
409
410    /*  don't rename these  */
411    DtLastChar(p, &cptr, &len);
412
413    if (!strcmp (p, ".") || !strcmp (p, "..") ||
414        !strcmp (p, "")  || ((len == 1) && (*cptr == '/')))
415    {
416       if (errorHandler)
417       {
418          char * tmpStr;
419
420          tmpStr = (GETMESSAGE(11,32, "Cannot rename %s"));
421          msg = XtNewString(tmpStr);
422          (*errorHandler) (w, msg, p);
423          XtFree(msg);
424       }
425       XtFree(targetDir);
426       return (False);
427    }
428
429
430    /*  parent doesn't exist  */
431    if((val = stat (_DtPName (source), &s1)) < 0)
432       val = lstat (_DtPName (source), &s1);
433
434    if((val1 = stat (_DtPName (target), &s2)) < 0)
435       val1 = lstat (_DtPName (target), &s2);
436
437    if (val < 0 || val1 < 0)
438    {
439       if (errorHandler)
440       {
441          tmpStr = GETMESSAGE(11, 14, "Cannot find the folders location.");
442          msg = XtNewString(tmpStr);
443          (*errorHandler) (w, msg, NULL);
444          XtFree(msg);
445       }
446       XtFree(targetDir);
447       return (False);
448    }
449
450
451    /*  check for target parent not writeable  */
452    if (CheckAccess(_DtPName (target), W_OK) == -1)
453    {
454       if (errorHandler)
455       {
456          char * tmpStr;
457
458          tmpStr = GetSharedMessage(CANT_WRITE_ERROR);
459          msg = XtNewString(tmpStr);
460          (*errorHandler) (w, msg, targetDir);
461          XtFree(msg);
462       }
463       XtFree(targetDir);
464       return (False);
465    }
466
467
468    /* check for source parent not writeable */
469    if (CheckAccess(_DtPName (source), W_OK) == -1)
470    {
471       if (errorHandler)
472       {
473          char * tmpStr;
474
475          tmpStr = GetSharedMessage(CANT_WRITE_ERROR);
476          msg = XtNewString(tmpStr);
477          (*errorHandler) (w, msg, source);
478          XtFree(msg);
479       }
480       XtFree(targetDir);
481       return (False);
482    }
483    /*
484      if (((sourceStatInfo->st_mode & S_IFMT) == S_IFDIR) &&
485      (CheckAccess(source, W_OK) != 0))
486      {
487      if (errorHandler)
488      {
489      char * tmpStr;
490
491      tmpStr=GETMESSAGE(11, 57,"You do not have permission to move the folder\n%s\nWrite permission is required.");
492      msg = XtMalloc(strlen(tmpStr) + strlen(source) + 2);
493      sprintf(msg, tmpStr, source);
494      (*errorHandler) (w, msg, source);
495      XtFree(msg);
496      }
497      XtFree(targetDir);
498      return (False);
499      }
500      */
501    /*  if parents are not on the same device, do a copy & delete */
502    if (s1.st_dev != s2.st_dev)
503    {
504       /* Determine correct Geometry Placement fo Move Dialog */
505       /* @@@ ... to be added */
506
507       child_pid = fork();
508       if (child_pid == -1)
509       {
510          if (errorHandler)
511          {
512             tmpStr = GETMESSAGE(11, 39, "Cannot create child process.\nThe maximum number of processes for this system has been reached.\nStop some of the processes or programs that are currently\nrunning and then retry this function.");
513             msg = XtNewString(tmpStr);
514             (*errorHandler) (w, msg, NULL);
515             XtFree(msg);
516          }
517          XtFree(targetDir);
518          return False;
519       }
520
521       if (child_pid == 0)
522       {
523          DBGFORK(("%s:  child forked\n", pname));
524
525          /* pass in geometry, and other command lines params when available */
526          if(type == TRASH_DIRECTORY)
527            rc = execlp(DTCOPY, "dtfile_copy", "-move", "-confirmReplace",
528                  "-confirmErrors", "-popDown","-checkPerms", source, target, NULL);
529          else
530            rc = execlp(DTCOPY, "dtfile_copy", "-move", "-confirmReplace",
531                  "-confirmErrors", "-popDown", source, target, NULL);
532
533          /* call errorhandler */
534          perror ("Could not exec child process \"dtfile_copy\"");
535
536          DBGFORK(("%s:  child exiting\n", pname));
537
538          exit (1);
539       }
540
541       DBGFORK(("%s:  forked child<%d>\n", pname, child_pid));
542
543
544       XtFree(targetDir);
545       return (True);
546    }
547
548    link_path = _DtFollowLink(source);
549
550
551    if (s1.st_ino != s2.st_ino)
552    { /*  different parent inodes  */
553      (void) lstat (source, &s1); /* get source dir ino */
554
555
556      if (Check (w, _DtPName (target), s1.st_ino, MOVE_FILE, errorHandler))
557      { /* move into self */
558        XtFree(targetDir);
559        return(False);
560      }
561    }
562
563 /*   This part of code was implemented with the idea that the links
564      to be treated differently.  So, it has to be uncommented whenever
565      links are handled differently (i.e., moving a link shall move the
566      absolute object.
567
568    if(strcmp(link_path, source) != 0)
569    {
570      if (RunFileCommand (MOVE_CMD, link_path, target, NULL) == 0)
571      {
572        XtFree(targetDir);
573        return (True);
574      }
575    }
576    else
577 */
578    {
579      if (RunFileCommand (MOVE_CMD, source, target, NULL) == 0)
580      {
581        XtFree(targetDir);
582        return (True);
583      }
584    }
585
586    XtFree(targetDir);
587    return (False);
588 }
589
590
591 /************************************************************************
592  *
593  *  CopyDir
594  *
595  ************************************************************************/
596 static Boolean
597 CopyDir(
598         Widget w,
599         int mode,
600         register char *from,
601         register char *to,
602         Boolean  isContainer,
603         struct stat *s1,
604         void (*errorHandler)(),
605         Boolean checkForBusyDir,
606         int type )
607 {
608    static char *pname = "CopyDir";
609    char * cptr;
610    int len;
611    char target [MAX_PATH];      /* buffer to hold the full file name */
612    char target_dir [MAX_PATH], target_file [MAX_PATH];
613    struct stat  s2;             /* status of to file   */
614    int child_pid, rc, target_rc;
615    char *msg, *tmpStr;
616
617    /* Check if source is readable */
618    if (CheckAccess(from, R_OK) == -1)
619    {
620       if (errorHandler)
621       {
622          tmpStr = GetSharedMessage(CANT_READ_ERROR);
623          msg = XtNewString(tmpStr);
624          (*errorHandler) (w, msg, from);
625          XtFree(msg);
626       }
627       return (False);
628    }
629
630    /* generate target name */
631    /* "to" can be something to copy the source into (isContainer=TRUE)     */
632    /*    or it can be the full path of the destination (isContainer=FALSE) */
633    /* the former case is probably more common (e.g. a drag&drop copy)      */
634    /*    whereas the second case occurs when, for example, the menu is     */
635    /*    to copy directory /u/joe/a to /u/joe/b (not doable with d&d)      */
636    (void) strcpy (target, to);
637    if (isContainer)
638    {
639       DtLastChar(to, &cptr, &len);
640       if ((len != 1) || (*cptr != '/'))
641           (void) strcat (target, "/");
642       (void) strcat (target, DName (from));
643    }
644    split_path(target, target_dir, target_file);
645
646    /* Check if target directory exists */
647    if ((target_rc = stat (target, &s2)) < 0)
648       target_rc = lstat(target, &s2);
649
650    if (target_rc >= 0)
651    {
652       /* target exists:
653        * make sure it's a directory */
654
655       if ((s2.st_mode & S_IFMT) != S_IFDIR)     /* target not directory */
656       {
657          if (errorHandler)
658          {
659             tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
660             msg = XtNewString(tmpStr);
661             (*errorHandler) (w, msg, target);
662             XtFree(msg);
663          }
664          return (False);
665       }
666    }
667    else
668    {
669      /* target does not exist:
670       * make sure the "to" directory exists and is writable */
671      if ((rc = stat (target_dir, &s2)) < 0)
672         rc = lstat(target_dir, &s2);
673
674      if (rc < 0 || (s2.st_mode & S_IFMT) != S_IFDIR)
675      {
676         if (errorHandler)
677         {
678            tmpStr = GETMESSAGE(11, 14, "Cannot find the folders location.");
679            msg = XtNewString(tmpStr);
680            (*errorHandler) (w, msg, NULL);
681            XtFree(msg);
682         }
683         return (False);
684      }
685
686      if (CheckAccess(target_dir, W_OK) == -1)
687      {
688         if (errorHandler)
689         {
690            tmpStr = GetSharedMessage(CANT_WRITE_ERROR);
691            msg = XtNewString(tmpStr);
692            (*errorHandler) (w, msg, to);
693            XtFree(msg);
694         }
695         return (False);
696      }
697    }
698
699    /* Determine if we are attempting a copy into self */
700    if (s1->st_dev == s2.st_dev)
701    {
702      if (target_rc >= 0)
703      {
704         if (Check (w, to, s1->st_ino, COPY_FILE, errorHandler))
705            return False;
706      }
707      else  /* destination dir does not exist, look at its proposed parent */
708      {
709         if (Check (w, target_dir, s1->st_ino, COPY_FILE, errorHandler))
710            return False;
711      }
712    }
713
714    /* Determine correct Geometry Placement fo Copy Dialog */
715    /* @@@ ... to be added */
716
717    /* If all the above checks have passed, then fork off the copy dialog */
718
719    child_pid = fork();
720    if (child_pid == -1)
721    {
722       if (errorHandler)
723       {
724          tmpStr = GETMESSAGE(11, 39, "Cannot create child process.\nThe maximum number of processes for this system has been reached.\nStop some of the processes or programs that are currently\nrunning and then retry this function.");
725          msg = XtNewString(tmpStr);
726          (*errorHandler) (w, msg, NULL);
727          XtFree(msg);
728       }
729       return False;
730    }
731
732    if (child_pid == 0)
733    {
734       DBGFORK(("%s:  child forked\n", pname));
735
736       /* pass in geometry, and other command lines params when available */
737       if (mode == MERGE_DIR)
738         /* merge source & target directories */
739         rc = execlp(DTCOPY, "dtfile_copy",
740                      "-dontDelete", "-forceCopies", "-copyTop",
741                      "-confirmReplace", "-confirmErrors", "-popDown",
742                      from, target, 0);
743       else
744          /* replace target dir */
745          rc = execlp(DTCOPY, "dtfile_copy",
746                      "-forceCopies", "-copyTop",
747                      "-confirmErrors", "-popDown",
748                      from, target, 0);
749
750       /* call errorhandler */
751       perror ("Could not exec child process \"dtfile_copy\"");
752
753       DBGFORK(("%s:  child exiting\n", pname));
754
755       exit (1);
756    }
757
758    DBGFORK(("%s:  forked child<%d>\n", pname, child_pid));
759
760
761    return TRUE;
762 }
763
764
765 /************************************************************************
766  *
767  *  FileManip
768  *
769  ************************************************************************/
770 Boolean
771 FileManip(
772         Widget w,
773         int mode,
774         register char *from,
775         register char *to,
776         Boolean  isContainer,          /* described in function CopyDir */
777         void (*errorHandler)(),
778         Boolean checkForBusyDir,
779         int type )
780 {
781    register int fold;
782    register int fnew;
783    register int n;
784    Boolean copy_dir_return;
785    Boolean move_dir_return;
786    void (*oldInt)();
787    void (*oldQuit)();
788    void (*oldPipe)();
789    void (*oldTerm)();
790    char * cptr;
791    int len;
792    Boolean restricted = False;
793    Boolean fileExists = False;
794
795    struct stat s1;      /* status of from file e.g. lstat info */
796    struct stat s4;      /* status of from file e.g. stat info  */
797    struct stat s2;      /* status of to file e.g.   stat info  */
798    struct stat s3;      /* status of to file e.g.   lstat info */
799
800    char buf [BLOCK_SIZE];               /* generic buffer */
801    char filename [MAX_PATH];            /* buffer to hold the full file name */
802    char * msg;
803    int link_result;
804    char * realTarget;
805    char * tmpStr;
806
807
808    /* Check the <from> part of the command:
809     *
810     * Report error if <from> doesn't exist.
811     * Else error if <from> hasn't read access.
812     */
813
814    DPRINTF(("FileManip: mode %d type %d from \"%s\" to \"%s\"\n", mode, type, from, to));
815    if (stat (from, &s1) < 0)
816    {
817       if (lstat (from, &s1) < 0)
818       {
819          if (errorHandler)
820          {
821             tmpStr = (GETMESSAGE(11,28, "%s cannot be found."));
822             msg = XtNewString(tmpStr);
823             (*errorHandler) (w, msg, from);
824             XtFree(msg);
825          }
826          return (False);
827       }
828    }
829
830    /* We will check if we need to initiate a copy of a directory */
831    if ((s1.st_mode & S_IFMT) == S_IFDIR)        /* from is a directory */
832    {
833       if (mode == COPY_FILE  ||  mode == MERGE_DIR)
834       {
835          oldInt = signal (SIGINT, SIG_IGN);
836          oldQuit = signal (SIGQUIT, SIG_IGN);
837          oldPipe = signal (SIGPIPE, SIG_IGN);
838          oldTerm = signal (SIGTERM, SIG_IGN);
839
840          copy_dir_return = CopyDir(w, mode, from, to, isContainer, &s1,
841                                    errorHandler, checkForBusyDir, type);
842
843          (void) signal (SIGINT, oldInt);
844          (void) signal (SIGQUIT, oldQuit);
845          (void) signal (SIGPIPE, oldPipe);
846          (void) signal (SIGTERM, oldTerm);
847
848          return (copy_dir_return);
849       }
850
851
852       /*  If the directory has more than one open view or open views  */
853       /*  of sub directories.  Then do not allow the move or rename.  */
854
855       if (mode == MOVE_FILE)
856       {
857          if (checkForBusyDir && DirectoryBusy (from))
858          {
859             if (errorHandler)
860             {
861                char message_buf[512];
862                char * tmpStr;
863
864                message_buf[0] = '\0';
865                tmpStr = (GETMESSAGE(11,30, "Cannot move or rename the folder %s.\nAll File Manager views displayed for a folder or its sub-folders\nmust be closed before a folder can be moved or renamed."));
866                sprintf (message_buf, tmpStr, from);
867                (*errorHandler) (w, message_buf, NULL);
868             }
869             return (False);
870          }
871
872
873          oldInt = signal (SIGINT, SIG_IGN);
874          oldQuit = signal (SIGQUIT, SIG_IGN);
875          oldPipe = signal (SIGPIPE, SIG_IGN);
876          oldTerm = signal (SIGTERM, SIG_IGN);
877
878          move_dir_return = MoveDir (w, from, to, &s1, errorHandler, &realTarget,type);
879
880          (void) signal (SIGINT, oldInt);
881          (void) signal (SIGQUIT, oldQuit);
882          (void) signal (SIGPIPE, oldPipe);
883          (void) signal (SIGTERM, oldTerm);
884
885          return (move_dir_return);
886       }
887
888       if (mode == LINK_FILE)
889       {
890          /* Need to append the directory name on */
891          (void) strcpy(filename, to);
892          if(type == DESKTOP)
893          {
894              char *tmp, *ptr;
895
896              tmp = (char *)XtMalloc(strlen(filename) + 1);
897              strcpy(tmp, filename);
898              /* get the workspace number first */
899              ptr = strrchr(tmp, '/');
900              *ptr = '\0';
901              /* now get the Desktop */
902              ptr = strrchr(tmp, '/');
903
904              /* if we don't get "/Desktop" then there is another filename
905                 attached to the end of the to name passed in */
906              if(strcmp(ptr, "/Desktop") != 0)
907                 restricted = True;
908              XtFree(tmp);
909          }
910
911          if( (!restricted && type != TRASH_DIRECTORY) && isContainer)
912          {
913             DtLastChar(to, &cptr, &len);
914             if ((len != 1) || (*cptr != '/'))
915                (void) strcat(filename, "/");
916          }
917
918          if(strcmp(from, "/.") == 0 || strcmp(from, "/") == 0)
919          {
920             (void) strcat(filename, home_host_name);
921             (void) strcat(filename, ":");
922             (void) strcat(filename, root_title);
923          }
924          else if ( (!restricted && type != TRASH_DIRECTORY) && isContainer)
925            (void) strcat(filename, DName(from));
926
927          to = filename;
928
929          if (((link_result = symlink(from, to)) != 0) && errorHandler)
930          {
931             if(type == NOT_DESKTOP || errno != EEXIST )
932             {
933                char * tmpStr;
934
935                tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
936                msg = XtNewString(tmpStr);
937                (*errorHandler) (w, msg, to);
938                XtFree(msg);
939             }
940          }
941
942          return(link_result == 0 ? True : False);
943       }
944    }
945
946    if (CheckAccess(from, R_OK) == -1)
947    {
948       /*
949        * A move operation does not require read permission, but a copy does.
950        */
951       if (mode == COPY_FILE)
952       {
953          if (errorHandler)
954          {
955             char * tmpStr;
956
957             tmpStr = GetSharedMessage(CANT_READ_ERROR);
958             msg = XtNewString(tmpStr);
959             (*errorHandler) (w, msg, from);
960             XtFree(msg);
961          }
962          return (False);
963       }
964    }
965
966
967    /* Here <from> is a file (not a directory).
968     * Check the <to> part of the command:
969     *
970     * <To> can either be an existing file,
971     *                    an existing directory,
972     *                    or a new file in an existing directory.
973     */
974
975    if (lstat (to, &s2) >= 0)                       /* <to> exists */
976    {
977       if ((stat (to, &s3) >= 0) &&
978 #if defined(__ultrix) || defined(__linux__) || \
979         defined(CSRG_BASED)
980            (((s3.st_mode & S_IFMT) == S_IFDIR)          /* if is a directory */
981            || ((s3.st_mode & S_IFMT) == S_IFSOCK)) )    /* or a net special */
982 #else
983 #if defined(SVR4) || defined(_AIX)
984            ((s3.st_mode & S_IFMT) == S_IFDIR) )         /* if is a directory */
985 #else  /* (__hpux) */
986            (((s3.st_mode & S_IFMT) == S_IFDIR)          /* if is a directory */
987            || ((s3.st_mode & S_IFMT) == S_IFNWK)) )     /* or a net special */
988 #endif
989 #endif
990       {                                            /* then get file name */
991             (void) strcpy (filename, to);
992
993             DtLastChar(to, &cptr, &len);
994             if ((len != 1) || (*cptr != '/'))
995                 (void) strcat (filename, "/");
996
997             (void) strcat (filename, DName (from));
998
999             to = filename;
1000       }
1001
1002       if (lstat (to, &s2) >= 0)                    /* reverify <to> exists */
1003       {
1004          if ((stat (to, &s3) >= 0) &&
1005              ((s3.st_mode & S_IFMT) == S_IFDIR))   /* if is a directory */
1006          {
1007             if (errorHandler)
1008             {
1009                char * tmpStr;
1010
1011                tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
1012                msg = XtNewString(tmpStr);
1013                (*errorHandler) (w, msg, to);
1014                XtFree(msg);
1015             }
1016             return (False);
1017          }
1018
1019
1020          /*  <from> = <to> NOOP.  */
1021
1022          if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino)
1023             return (True);
1024
1025
1026          /*  no write permission  */
1027          if (CheckAccess(to, W_OK) == -1)
1028          {
1029             char *link_path;
1030
1031             link_path = _DtFollowLink(to);
1032             if(strcmp(to,link_path) == 0)
1033             {
1034                if (errorHandler)
1035                {
1036                   char * tmpStr;
1037
1038                   tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
1039                   msg = XtNewString(tmpStr);
1040                   (*errorHandler) (w, msg, to);
1041                   XtFree(msg);
1042                }
1043                return (False);
1044             }
1045          }
1046
1047
1048          /*  unlink failed  */
1049
1050          if (unlink (to) < 0)
1051          {
1052             if (errorHandler)
1053             {
1054                char * tmpStr;
1055
1056                tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
1057                msg = XtNewString(tmpStr);
1058                (*errorHandler) (w, msg, to);
1059                XtFree(msg);
1060             }
1061             return (False);
1062          }
1063          fileExists = True;
1064       }
1065    }
1066
1067
1068    /* Here <from> is a file and <to> doesn't exist.
1069     *
1070     * If not a copy, link the files.  If the link succeeds, unlink
1071     *   <from> and return.
1072     * Copy <from> to <to>.
1073     * If the copy cmd is not specified, unlink <from>.
1074     */
1075
1076    if (mode != COPY_FILE)
1077    {
1078       /* Try to maintain symbolic links, except when we're doing a link! */
1079       if (((s1.st_mode & S_IFMT) == S_IFLNK) && (mode != LINK_FILE))
1080       {
1081          char link_path[MAX_PATH + 1];
1082          int link_len;
1083
1084          if ((link_len = readlink(from, link_path, MAX_PATH)) > 0)
1085          {
1086             link_path[link_len] = '\0';
1087             link_result = symlink(link_path, to);
1088          }
1089          else
1090          {
1091             /* Fail-safe; do it the hard way */
1092             if (mode == MOVE_FILE)
1093                if (RunFileCommand(MOVE_CMD, from, to, NULL) == 0)
1094                   return(True);
1095             else
1096                if (RunFileCommand(LINK_CMD, "-s", from, to) == 0)
1097                   return(True);
1098
1099             link_result = (-1);
1100          }
1101       }
1102       else
1103       {
1104          if (mode == LINK_FILE)
1105             link_result = symlink(from, to);
1106          else
1107          {
1108             char *link_path;
1109
1110             link_path = _DtFollowLink(from);
1111
1112             if(strcmp(link_path, from) != 0)
1113                  link_result = symlink(link_path, to);
1114             else
1115                  link_result = link (from, to);
1116          }
1117       }
1118
1119       /* If this was a link, then time to bail out */
1120       if (mode == LINK_FILE)
1121       {
1122          if ((link_result != 0) && errorHandler)
1123          {
1124             char * tmpStr;
1125
1126             tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
1127             msg = XtNewString(tmpStr);
1128             (*errorHandler) (w, msg, to);
1129             XtFree(msg);
1130          }
1131
1132          return(link_result == 0 ? True : False);
1133       }
1134
1135       /* Unlink source only if this was a move request */
1136       if ((mode == MOVE_FILE) && (link_result >= 0))
1137       {
1138          if (unlink (from) < 0)
1139          {
1140             if (errorHandler)
1141             {
1142                char * tmpStr;
1143
1144                tmpStr = GetSharedMessage(CANT_DELETE_ERROR);
1145                msg = XtNewString(tmpStr);
1146                (*errorHandler) (w, msg, from);
1147                XtFree(msg);
1148             }
1149             (void) unlink (to);
1150             return (False);
1151          }
1152
1153          return (True);
1154       }
1155    }
1156
1157    /*  unable to read <from>  */
1158
1159    if ((fold = open (from, O_RDONLY)) < 0)
1160    {
1161       if (errorHandler)
1162       {
1163          char * tmpStr;
1164
1165          tmpStr = GetSharedMessage(CANT_READ_ERROR);
1166          msg = XtNewString(tmpStr);
1167          (*errorHandler) (w, msg, from);
1168          XtFree(msg);
1169       }
1170       return (False);
1171    }
1172
1173
1174    /*  unable create <to>  */
1175
1176
1177    /* We use the stat buffer info not lstat info */
1178    (void) stat (from, &s4);
1179
1180    if ((fnew = creat (to, (int) s4.st_mode)) < 0)
1181    {
1182       if (errorHandler)
1183       {
1184          char * tmpStr;
1185
1186          tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
1187          msg = XtNewString(tmpStr);
1188          (*errorHandler) (w, msg, to);
1189          XtFree(msg);
1190       }
1191       (void) close (fold);
1192       return (False);
1193    }
1194
1195    /*  do the copy  */
1196
1197
1198    while (n = read (fold, buf, BLOCK_SIZE))
1199    {
1200      int result;
1201
1202      if (n < 0)
1203      {
1204        if (errorHandler)
1205        {
1206          tmpStr = (GETMESSAGE(11,31, "Error while reading %s"));
1207          msg = XtNewString(tmpStr);
1208          (*errorHandler) (w, msg, to);
1209          XtFree(msg);
1210        }
1211        (void) close (fold);
1212        (void) close (fnew);
1213        return (False);
1214      }
1215
1216      errno = 0;
1217      result = write(fnew, buf, n);
1218      if (result != n)
1219      {
1220        (void) close (fold);
1221        (void) close (fnew);
1222        if(errno)
1223        {
1224          char * strerrormsg = NULL;
1225          char * catmsg = NULL;
1226          char * samsg = NULL;
1227          char errnoMsg[25];
1228          Boolean unknown = False;
1229          int bufLen;
1230
1231          switch (errno)
1232          {
1233 #ifdef EDQUOT
1234              case EDQUOT:
1235              {
1236                  if(mode == COPY_FILE)
1237                    tmpStr = (GETMESSAGE(11,51, "Unable to copy the file/folder because\nthe disk quota will be exceeded on the disk\nyou are copying it to."));
1238                  else
1239                    tmpStr = (GETMESSAGE(11,52, "Unable to move the file/folder because\nthe disk quota will be exceeded on the disk\nyou are moving it to."));
1240                  catmsg = XtNewString(tmpStr);
1241                  break;
1242              }
1243 #endif
1244              case ENOSPC:
1245                  {
1246                  if(mode == COPY_FILE)
1247                    tmpStr = (GETMESSAGE(11,42, "No space available on the\ndevice you are copying to.\n\n"));
1248                  else
1249                    tmpStr = (GETMESSAGE(11,43, "No space available on the\ndevice you are moving to.\n"));
1250                  catmsg = XtNewString(tmpStr);
1251                  break;
1252                  }
1253              case EAGAIN:
1254                  sprintf(errnoMsg, "EAGAIN:  ");
1255                  strerrormsg = strerror(errno);
1256                  break;
1257              case EBADF:
1258                  sprintf(errnoMsg, "EBADF:  ");
1259                  strerrormsg = strerror(errno);
1260                  break;
1261              case EDEADLK:
1262                  sprintf(errnoMsg, "EDEADLK:  ");
1263                  strerrormsg = strerror(errno);
1264                  break;
1265              case EINTR:
1266                  sprintf(errnoMsg, "EINTR:  ");
1267                  strerrormsg = strerror(errno);
1268                  break;
1269              case EIO:
1270                  sprintf(errnoMsg, "EIO:   ");
1271                  strerrormsg = strerror(errno);
1272                  break;
1273              case ENOLCK:
1274                  sprintf(errnoMsg, "ENOLCK:  ");
1275                  strerrormsg = strerror(errno);
1276                  break;
1277              case EPIPE:
1278                  sprintf(errnoMsg, "EPIPE:  ");
1279                  strerrormsg = strerror(errno);
1280                  break;
1281              default:
1282                  unknown = True;
1283                  sprintf(errnoMsg, "%s", GETMESSAGE(11,56, "(Unknown):"));
1284                  strerrormsg = strerror(errno);
1285                  break;
1286          }
1287
1288          /* If catmsg is NULL then one of the miscellanous error's occurred.
1289           * Set up a generic error message which will output the internal
1290           * error message.
1291           */
1292          if(catmsg == NULL)
1293          {
1294            if(mode == COPY_FILE)
1295              tmpStr = (GETMESSAGE(11,53, "The copy of the file/folder failed\ndue to some internal error. The internal\nerror given is:"));
1296            else
1297              tmpStr = (GETMESSAGE(11,54, "The move of the file/folder failed\ndue to some internal error. The internal\nerror given is:"));
1298            catmsg = XtNewString(tmpStr);
1299            tmpStr = (GETMESSAGE(11,55, "Please see your System Administrator"));
1300            samsg = XtNewString(tmpStr);
1301          }
1302
1303          /* Build a concatination of the possible message parts */
1304          bufLen = (strerrormsg ? strlen(strerrormsg) +
1305                    strlen(errnoMsg) + strlen(samsg) : 0) +
1306                    strlen(catmsg) + 10;
1307          msg = XtMalloc(bufLen);
1308          strcpy (msg, catmsg);
1309          if (strerrormsg)
1310          {
1311            strcat (msg, "\n\n");
1312            strcat (msg, errnoMsg);
1313            if(unknown)
1314              strcat (msg, "  ");
1315            strcat (msg, strerrormsg);
1316            strcat (msg, "\n\n");
1317            strcat (msg, samsg);
1318          }
1319
1320          (*errorHandler) (w, msg, to);
1321          XtFree(msg);
1322          XtFree(catmsg);
1323        }
1324        unlink(to);
1325        return (False);
1326      }
1327    }
1328
1329    (void) close (fold);
1330    (void) close (fnew);
1331
1332
1333    /*  unlink <from> if not copy  */
1334
1335    if (mode == MOVE_FILE)
1336    {
1337       if (unlink (from) < 0)
1338       {
1339          if (errorHandler)
1340          {
1341             char *tmpStr, *ptr;
1342
1343
1344             ptr = strrchr(from, '/') + 1;
1345             tmpStr = (GETMESSAGE(11,38, "You do not have permission to move %s\nHowever, you can copy the object.\nTo copy an object:\n  - press and hold the <Ctrl> key, and\n  - drag the object with your mouse.\nOr\n  - use 'Copy To' in the 'Selected' menu popup of the menu bar."));
1346             msg = XtNewString(tmpStr);
1347             (*errorHandler) (w, msg, ptr);
1348             XtFree(msg);
1349             unlink(to);
1350          }
1351          return (False);
1352       }
1353    }
1354
1355
1356    /*
1357     * WARNING: this is different from how the shell behaves.  If you use
1358     *          a shell to copy over an existing file, the file keeps its
1359     *          original owner and group; for some historical reason,
1360     *          dtfile does it differently.
1361     *   UPDATE:  This is no longer the case as of 10/31/94, we change the
1362     *            file to the original owner and group now. This is to fix
1363     *            a bug.
1364     *          Also, this call originally occurred after we opened/created
1365     *          the file, but before we closed it.  This caused problems
1366     *          if the user was running as root, and was copying across
1367     *          an nfs link, since root access is not typically carried
1368     *          across an nfs mount.  The result was that we were able to
1369     *          create the file, copy to it, but when we tried to close it,
1370     *          because the file was now owned by root on the other system,
1371     *          we could not close the file; thus, the file ended up empty!
1372     */
1373
1374    if (mode == COPY_FILE && fileExists)
1375    {
1376       /*  set for user  */
1377       (void) chmod (to, s3.st_mode);
1378       (void) chown (to, s3.st_uid, s3.st_gid);
1379    }
1380    else
1381    {
1382       /*  set for user  */
1383       (void) chown (to, getuid(), getgid());
1384    }
1385
1386    return (True);
1387 }