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