remove OSF1 support
[oweals/cde.git] / cde / programs / dtfile / dtcopy / sharedFuncs.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: sharedFuncs.c /main/9 1998/04/06 13:15:57 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           sharedFuncs.c
28  *
29  *
30  *   DESCRIPTION:    Common functions for both dtfile and dtfile_copy
31  *
32  *   FUNCTIONS: CreateDefaultImage
33  *              ImageInitialize
34  *              auto_rename
35  *              build_path
36  *              generate_NewPath
37  *              split_path
38  *
39  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
40  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
41  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
42  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
43  *
44  ****************************************************************************
45  ************************************<+>*************************************/
46
47 #if defined(SVR4)
48 #  include <sys/fs/ufs_fs.h>
49 #  define ROOTINO UFSROOTINO
50 #endif  /* SVR4 */
51
52 #if defined(linux) || defined(CSRG_BASED)
53 #  include <sys/param.h>
54 #  define ROOTINO 2
55 #endif
56
57
58 #include <string.h>
59 #include <sys/stat.h>
60 #include <stdio.h>
61 #include <errno.h>
62 #include <sys/types.h>
63 #include <sys/mount.h>
64 #include <pwd.h>
65 #include <fcntl.h>
66 #if !defined(CSRG_BASED)
67 #include <ustat.h>
68 #endif
69 #include <dirent.h>
70
71
72 #include <Xm/Xm.h>
73
74 #include <Xm/Form.h>
75 #include <Xm/PushB.h>
76
77 #include <Dt/Connect.h>
78 #include <Dt/DtNlUtils.h>
79 #include <Dt/SharedProcs.h>
80
81 #include "sharedFuncs.h"
82 #include "dtcopy.h"
83
84
85
86 /************************************************************************
87  *  Bitmap Data for Default Symbol
88  **********************************<->***********************************/
89
90 static unsigned char errorBits[] = {
91    0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0xf0, 0x3a, 0x00, 0x58, 0x55, 0x00,
92    0x2c, 0xa0, 0x00, 0x56, 0x40, 0x01, 0xaa, 0x80, 0x02, 0x46, 0x81, 0x01,
93    0x8a, 0x82, 0x02, 0x06, 0x85, 0x01, 0x0a, 0x8a, 0x02, 0x06, 0x94, 0x01,
94    0x0a, 0xe8, 0x02, 0x14, 0x50, 0x01, 0x28, 0xb0, 0x00, 0xd0, 0x5f, 0x00,
95    0xa0, 0x2a, 0x00, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
96
97 static unsigned char infoBits[] = {
98    0x00, 0x00, 0x78, 0x00, 0x54, 0x00, 0x2c, 0x00, 0x54, 0x00, 0x28, 0x00,
99    0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x2a, 0x00, 0x5c, 0x00, 0x28, 0x00,
100    0x58, 0x00, 0x28, 0x00, 0x58, 0x00, 0x28, 0x00, 0x58, 0x00, 0x28, 0x00,
101    0x58, 0x00, 0xae, 0x01, 0x56, 0x01, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00};
102
103 static unsigned char questionBits[] = {
104    0xf0, 0x3f, 0x00, 0x58, 0x55, 0x00, 0xac, 0xaa, 0x00, 0xd6, 0x5f, 0x01,
105    0xea, 0xbf, 0x02, 0xf6, 0x7f, 0x01, 0xea, 0xba, 0x02, 0xf6, 0x7d, 0x05,
106    0xea, 0xba, 0x0a, 0x56, 0x7d, 0x15, 0xaa, 0xbe, 0x1e, 0x56, 0x5f, 0x01,
107    0xac, 0xaf, 0x02, 0x58, 0x57, 0x01, 0xb0, 0xaf, 0x00, 0x60, 0x55, 0x01,
108    0xa0, 0xaa, 0x00, 0x60, 0x17, 0x00, 0xa0, 0x2f, 0x00, 0x60, 0x17, 0x00,
109    0xb0, 0x2a, 0x00, 0x50, 0x55, 0x00};
110
111 static unsigned char warningBits[] = {
112    0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x56, 0x00, 0x2a, 0x00, 0x56, 0x00,
113    0x2a, 0x00, 0x56, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x2c, 0x00, 0x14, 0x00,
114    0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x14, 0x00,
115    0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00};
116
117 static unsigned char workingBits[] = {
118    0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xaa, 0xaa, 0x0a, 0x44, 0x55, 0x06,
119    0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06, 0xcc, 0x2a, 0x02, 0x84, 0x15, 0x06,
120    0x8c, 0x2a, 0x02, 0x04, 0x15, 0x06, 0x0c, 0x0a, 0x02, 0x04, 0x06, 0x06,
121    0x0c, 0x0b, 0x02, 0x84, 0x15, 0x06, 0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06,
122    0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06, 0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06,
123    0xfe, 0xff, 0x0f, 0x56, 0x55, 0x05, 0x00, 0x00, 0x00};
124
125 Widget G_toplevel;
126 int    G_dialog_closed = FALSE;
127
128 /*----------------------------------------------------------
129  *
130  *  split_path
131  *
132  *  Given a path, return a pointer to the directory (folder)
133  *  and file (object). On error, both will be set to empty
134  *  strings.
135  *
136  *  The calling routine is responsible for allocating space
137  *  for object and folder.
138  *
139  *  This function simply searches for the last slash (/) in
140  *  the path and returns the characters preceding the slash
141  *  as folder and the characters after the last slash as
142  *  object. Thus, object could be a directory/folder or a
143  *  file.
144  *
145  *  There is a complimentary function, build_path, to put
146  *  object and folder back together to form a path.
147  *
148  *-----------------------------------------------------------*/
149
150 void
151 split_path(const String path, String folder, String object)
152
153 {
154
155    String lastSlash;
156
157    if ( (lastSlash = strrchr(path,'/')) != NULL)
158    {
159       strcpy(object,lastSlash+1);
160       if(lastSlash == path)  /* Must be root Folder */
161         strcpy(folder,"/");
162       else
163       {
164         *lastSlash = '\0';
165         strcpy(folder,path);
166         *lastSlash = '/';
167       }
168    }
169    else
170    {
171       folder[0] = object[0] = '\0';
172    }
173 }  /* end split_path */
174
175 char *
176 get_path(char *path)
177 {
178     char *rpath, tmppath[MAX_PATH];
179     char * _DtCopyPathFromInput();
180     if (!getcwd(tmppath,MAX_PATH))
181         return NULL;
182     rpath = _DtCopyPathFromInput(path,tmppath);
183     return rpath;
184 }
185
186 /*-----------------------------------------------------------------
187  *
188  *  build_path
189  *
190  *  Given a directory (folder) and file (object), build a string
191  *  with the complete path and return it.
192  *
193  *  The calling routine is responsible for freeing storage used
194  *  for the returned string.
195  *
196  *  There is a complimentary function, split_path, to take
197  *  path apart to form folder and object
198  *
199  *-----------------------------------------------------------------*/
200
201 String
202 build_path(const String folder, const String object)
203
204 {
205    char    s[MAX_PATH];
206    String  path;
207
208    strncpy(s, folder, MAX_PATH);
209    strncat(s, "/",    MAX_PATH-strlen(s));
210    strncat(s, object, MAX_PATH-strlen(s));
211    path = (String) malloc(strlen(s)+1);
212    strcpy(path,s);
213
214    return path;
215
216 }  /* end build_path */
217
218
219
220 /*--------------------------------------------------------------
221  *
222  *  auto_rename
223  *
224  *  Given a path, generate a new file name and rename the file.
225  *
226  *  The rc from the system call is returned and errno is set.
227  *
228  *--------------------------------------------------------------*/
229
230 int
231 auto_rename(const String path)
232
233 {
234    char newPath[MAX_PATH];
235
236    generate_NewPath(newPath,path);
237    errno = 0;
238    return (rename(path,newPath));
239
240 }  /* end auto_rename */
241
242
243 /*-----------------------------------------------------------------------
244  *
245  *  generate_NewPath
246  *
247  *  Given a path (and a complete path is required), append a
248  *  sequence number to generate a new file name. The new file
249  *  will not exist. The sequence number consists of a one-character
250  *  delimiter and an integer. The function will start with
251  *  1, if the file with 1 exists it will continue to 2, etc.
252  *  newPath and oldPath can point to the same area. The sequence number
253  *  is appended to the end of the name unless it contains a
254  *  dot, in which case the sequence number precedes the dot. For example,
255  *  /cde/dtfile/dtcopy/overwrtdialog.c becomes
256  *  /cde/dtfile/dtcopy/overwrtdialog~1.c. However, if the dot
257  *  is the first character in the file name, the sequence number is
258  *  appended, (e.g. .profile --> .profile~1).
259  *
260  *-----------------------------------------------------------------------*/
261
262 void
263 generate_NewPath(String newPath, String oldPath)
264
265 {
266
267    const char   delim = '_';
268
269    struct stat  buf;
270    String       lastDot, lastSlash;
271    char         firstPart[MAX_PATH], lastPart[MAX_PATH];
272    int          i = 0;
273    int          len;
274
275
276    lastDot   = strrchr(oldPath,'.');
277    lastSlash = strrchr(oldPath,'/');
278    if (lastSlash == NULL)
279       lastSlash = oldPath - 1;   /* allows for no path and first char is dot */
280    len = lastDot - oldPath;
281    if ( lastDot != NULL &&            /* no dot */
282         lastDot > lastSlash+1 &&      /* dot is in filename, not directory name */
283         len != strlen(oldPath)-1 )    /* dot is not last character of filename */
284    {
285       /* sequence number will be inserted before filename suffix */
286       memcpy(firstPart,oldPath,len);
287       firstPart[len] = '\0';
288       strcpy(lastPart,lastDot);
289    }
290    else
291    {
292       /* sequence number will be appended to filename */
293       strcpy(firstPart,oldPath);
294       lastPart[0] = '\0';
295    }
296
297
298    do
299    {
300       i++;
301       sprintf(newPath,"%s%c%d%s",firstPart,delim,i,lastPart);
302    } while (lstat(newPath,&buf) == 0);
303
304    return;
305
306
307 }  /* end generate_NewPath */
308
309
310 /****************************************************************
311  * Create a default images for symbol... used in ClassInitialize.
312  ****************/
313
314 XImage *
315 CreateDefaultImage(
316         Display *display,
317         char *bits,
318         unsigned int width,
319         unsigned int height )
320 {
321     XImage *image ;
322
323     image = XCreateImage(display,
324                          DefaultVisual(display, DefaultScreen(display)),
325                          1, XYBitmap, 0, bits, width, height, 8,
326                          (width+7) >> 3);
327     image->byte_order = LSBFirst;
328     image->bitmap_unit = 8;
329     image->bitmap_bit_order = LSBFirst;
330
331     return( image) ;
332 }  /* end CreateDefaultImage */
333
334
335
336 void
337 ImageInitialize( Display *display )
338 {
339     XImage *image;
340
341     /* create and install the default images for the symbol */
342
343     image = CreateDefaultImage (display, (char *)errorBits, 20, 20);
344     XmInstallImage (image, "default_xm_error");
345
346     image = CreateDefaultImage (display, (char *)infoBits, 11, 24);
347     XmInstallImage (image, "default_xm_information");
348
349     image = CreateDefaultImage (display, (char *)questionBits, 22, 22);
350     XmInstallImage (image, "default_xm_question");
351
352     image = CreateDefaultImage (display, (char *)warningBits, 9, 22);
353     XmInstallImage (image, "default_xm_warning");
354
355     image = CreateDefaultImage (display, (char *)workingBits, 21, 23);
356     XmInstallImage (image, "default_xm_working");
357
358     return ;
359 }  /*  end ImageInitialize */
360
361 #if !defined(CSRG_BASED)
362 static int
363 CopyFileSysType(
364    int dev)
365 {
366   struct ustat u1;
367   if(ustat(dev,&u1) < 0)
368      return -2;
369   return u1.f_tinode;
370 }
371 #endif
372
373 static int
374 CopyCheckDeletePermissionRecur(
375   char *destinationPath)
376 {
377   struct stat statbuf;
378   DIR *dirp;
379   struct dirent * dp;
380   Boolean first_file;
381   char *fnamep;
382
383   DPRINTF(("CheckDeletePermissionRecur(\"%s\")\n", destinationPath));
384
385   if (lstat(destinationPath, &statbuf) < 0)
386     return -1;  /* probably does not exist */
387
388   if (! S_ISDIR(statbuf.st_mode))
389   {
390     if(access(destinationPath,04) < 0)
391        return -1;
392     return 0;   /* no need to check anything more */
393   }
394
395   dirp = opendir (destinationPath);
396   if (dirp == NULL)
397     return -1;  /* could not read directory */
398
399
400   first_file = True;
401
402   while (dp = readdir (dirp))
403   {
404     if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
405     {
406       if (first_file)
407       {
408         /* check for write permission in this directory */
409         if (access(destinationPath, 04|02|01) < 0)
410         {
411             closedir(dirp);
412             return -1;
413         }
414
415         /* append a '/' to the end of directory name */
416         fnamep = destinationPath + strlen(destinationPath);
417         *fnamep++ = '/';
418
419         first_file = False;
420       }
421
422       /* append file name to end of directory name */
423       strcpy(fnamep, dp->d_name);
424
425       /* recursively check permission on this file */
426       if (CopyCheckDeletePermissionRecur(destinationPath))
427         {
428             closedir(dirp);
429             return -1;
430         }
431     }
432   }
433
434   closedir(dirp);
435   return 0;
436 }
437
438 static int
439 CopyCheckDeletePermission(
440   char *parentdir,
441   char *destinationPath)
442 {
443 #if defined(__FreeBSD__) || defined(__OpenBSD__)
444   struct statfs statbuf;
445 #elif defined(__NetBSD__)
446   struct statvfs statbuf;
447 #else
448   struct stat statbuf;
449 #endif
450   char fname[PATH_MAX];
451
452 #if defined(__FreeBSD__) || defined(__OpenBSD__)
453   if (statfs(parentdir,&statbuf) < 0)  /* does not exist */
454 #elif defined(__NetBSD__)
455   if (statvfs(parentdir,&statbuf) < 0)  /* does not exist */
456 #else
457   if (lstat(parentdir,&statbuf) < 0)  /* does not exist */
458 #endif
459     return -1;
460
461   /* check if we are root */
462   if (getuid() == 0)
463   {
464     /* if NFS, need to check if server trusts root */
465 #if defined(CSRG_BASED)
466     if (!strcmp(statbuf.f_fstypename, "nfs"))  /* Root user and nfs */
467 #else
468     if (CopyFileSysType(statbuf.st_dev) < 0)  /* Root user and nfs */
469 #endif
470     {
471        char *tmpfile;
472        int rv;
473        tmpfile = tempnam(parentdir,"dtfile");
474        if (tmpfile)
475        {
476            /* Create a temporary file */
477            if ( (rv = creat(tmpfile,O_RDONLY)) < 0)
478            {
479                free(tmpfile);
480                return -1;
481            }
482            close(rv);
483            /* Delete the created file */
484            if (remove(tmpfile) < 0)
485            {
486                free(tmpfile);
487                return -1;
488            }
489
490            free(tmpfile);
491        }
492        else
493            return -1;
494     }
495
496     /* root user can delete anything */
497     return 0;
498   }
499
500   /* check for read/write and execute permission on parent dir */
501   if (access(parentdir, R_OK | W_OK | X_OK) < 0)
502       return -1;
503
504   /* copy destinationPath to tmp buffer */
505   strcpy(fname, destinationPath);
506
507   return CopyCheckDeletePermissionRecur(fname);
508 }
509
510 void
511 CloseTopLevel(
512      Widget w,
513      void *client_data,
514      void *call_data)
515 {
516   XtDestroyWidget((Widget)G_toplevel);
517   exit(-1);
518 }
519
520 void
521 CheckDeleteAccess(
522      XtAppContext app_context,
523      int delay,
524      Boolean checkPerms,
525      Boolean move,
526      char *source_name)
527 {
528   if(checkPerms && move)
529   {
530      char title[200],*msg,*tmpmsg;
531      char *tmpstring = strdup(source_name),*tmpptr;
532      XEvent event;
533      int perm_status = 0;
534
535      delay = 10000;
536      tmpptr = strrchr(tmpstring,'/');
537      if(!tmpstring || !tmpptr)                               /* Error */
538        perm_status = 1;
539      else
540      {
541        if(tmpptr == tmpstring)
542           tmpptr = "/";
543        else
544        {
545          *tmpptr = '\0';
546          tmpptr = tmpstring;
547        }
548        perm_status = CopyCheckDeletePermission(tmpptr,source_name);
549        free(tmpstring);
550        tmpstring = NULL;
551      }
552      if(!perm_status)  /* Everything is fine just return */
553      {
554          return;
555      }
556
557      free(tmpstring);
558
559      strcpy(title,GETMESSAGE(4,7,"Object Trash - Error"));
560      tmpmsg =  GETMESSAGE(4,8,"You do not have permission to put the object \n\n%s\n\ninto trash.\n\nUse the Change Permissions choice from the object's\npopup menu or from the Selected menu to turn on your\nRead permission on the object.\n\nNote: If this object is a folder, you must also have\nRead permission for each of the objects inside the\nfolder before you can put the folder in the trash.");
561
562      msg = XtMalloc(strlen(tmpmsg)+strlen(source_name)+2);
563      sprintf(msg,tmpmsg,source_name);
564      _DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
565          CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
566 /*
567      XtAppAddTimeOut(app_context, delay, TimeoutHandler, NULL);
568 */
569
570     /* wait for user to close the dialog before exiting */
571      XtFree(msg);
572      while (!G_dialog_closed)
573      {
574          XtAppNextEvent(app_context, &event);
575          XtDispatchEvent(&event);
576      }
577   }
578 }
579
580 void
581 TimeoutHandler(XtPointer client_data, XtIntervalId *id)
582 {
583   exit(0);
584 }
585
586 /*
587  * This is a generic function for resolving a cannonical path from user input.
588  */
589
590 char *
591 _DtCopyPathFromInput(char *input_string, char *current_dir)
592 {
593     char *path = NULL;
594     char *tmp_path = NULL;
595     int dir_len;
596     char *_DtCopyChangeTildeToHome();
597
598     /* find relative path */
599
600     tmp_path = path = XtNewString(input_string);
601
602
603     /* Strip any spaces from name -- input is overwritten */
604     path = (char *) _DtStripSpaces(path);
605
606     /* Resolve, if there're any, environement variables */
607     {
608         FILE *pfp;
609         char command[MAX_PATH];
610
611         sprintf(command,"echo %s",path);
612         if((pfp=popen(command,"r")) == NULL)
613         {
614
615         }
616         else
617         {
618             if (fscanf(pfp,"%s",command) >= 1)
619             {
620                 XtFree(path);
621                 path = XtNewString(command);
622             }
623             else
624                 path = NULL;
625
626             pclose(pfp);
627         }
628     }
629
630     if (!path)
631         return NULL;
632
633     /* Resolve '~' -- new memory is allocated, old memory is freed */
634     if (*path == '~')
635         path = _DtCopyChangeTildeToHome(path);
636
637     /* If current dir provided, check for relative path */
638     if (path && current_dir)
639     {
640         if (*path != '/')
641         {
642             /* file is relative path i.e.      xyz/abc */
643             if (strcmp(current_dir, "/") == 0)
644             {
645                 tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 1);
646                 sprintf(tmp_path, "%s%s", current_dir, path);
647             }
648             else
649             {
650                 tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 2);
651                 sprintf(tmp_path, "%s/%s", current_dir, path);
652             }
653
654             XtFree(path);
655             path = tmp_path;
656             tmp_path = NULL;
657         }
658     }
659     else if (!path)
660     {
661         XtFree(tmp_path);
662         return NULL;
663     }
664
665     /* Resolve '.' or '..' -- input is overwritten, output may be NULL! */
666     /* Save pointer to path to free if output is NULL.                  */
667     tmp_path = path;
668     path = (char *) XeEliminateDots(path);
669
670     /* Strip off trailing '/' */
671     dir_len = strlen(path);
672     if (dir_len > 1 && *(path + dir_len - 1) == '/')
673         *(path + dir_len - 1) = '\0';
674     return path;
675 }
676 char *
677 #ifdef _NO_PROTO
678 _DtCopyChangeTildeToHome (input_string)
679     char *input_string;
680 #else
681     _DtCopyChangeTildeToHome (
682     char *input_string)
683 #endif
684 {
685     char *path;
686     char *full_path;
687     struct passwd * pwInfo;
688     char * homedir = (char *) XtNewString(getenv("HOME"));
689
690     if ((input_string[1] != '/'))
691     {
692         char *path;
693
694         /* ~user or ~user/path format */
695
696         /* is there a path? */
697         path = (char *) DtStrchr(input_string, '/');
698
699         /* find user */
700         if (path)
701             *path = '/';
702         if ((pwInfo = getpwnam(input_string + 1)) == NULL)
703         {
704             /* user doesn't exist */
705             if (path)
706                 *path = '/';
707             return NULL;
708         }
709
710         if (path)
711         {
712             /* ~user/path format */
713
714             *path = '/';
715
716             if (strcmp(pwInfo->pw_dir, "/") == 0)
717             {
718                 /* We don't want to end up with double '/' in the path */
719                 full_path = (char *) XtMalloc(strlen(path) + 1);
720                 strcpy(full_path, path);
721             }
722             else
723             {
724                 full_path = (char *) XtMalloc(strlen(pwInfo->pw_dir) +
725                                               strlen(path) + 1);
726                 sprintf(full_path, "%s%s", pwInfo->pw_dir, path);
727             }
728         }
729         else
730         {
731             /* ~user format */
732
733             full_path = XtMalloc(strlen(pwInfo->pw_dir) + 1);
734             strcpy(full_path, pwInfo->pw_dir);
735         }
736     }
737     else if (input_string[1])
738     {
739         /* ~/path format */
740
741         /* NOTE: users_home_dir has trailing '/' */
742         full_path = (char *) XtMalloc(strlen(homedir) + strlen(input_string+2) + 1);
743         sprintf(full_path, "%s%s", homedir, (input_string + 2));
744     }
745     else
746     {
747
748         /* ~ format */
749
750         full_path = XtMalloc(strlen(homedir) + 1);
751         strcpy(full_path, homedir);
752     }
753
754     XtFree(homedir);
755     XtFree(input_string);
756     return(full_path);
757 }
758
759 int
760 Check(char *spth, char *dpth, int mode)
761 {
762     struct stat sbuf, dbuf;
763     char filename [MAX_PATH];
764     char * msg;
765     char * tmpStr;
766     char title[300];
767
768     sbuf.st_ino = 0;
769     if (lstat (spth, &sbuf) < 0)
770     {
771         tmpStr = (GETMESSAGE(4,9, "Cannot open %s"));
772         msg = XtMalloc(strlen(tmpStr)+strlen(filename)+1);
773         sprintf(msg,tmpStr,filename);
774         _DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
775                           CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
776         XtFree(msg);
777         return 0;
778     }
779     (void) strcpy (filename, dpth);
780     if(mode)
781         strcpy(title,GETMESSAGE(4,5,"Object Move - Error"));
782     else
783         strcpy(title,GETMESSAGE(4,6,"Object Copy - Error"));
784
785     dbuf.st_ino = 0;
786     while (dbuf.st_ino != ROOTINO)
787     {
788         /* Destination may not be available, in which case we need to
789            create it, so just return as successful and the remaining
790            code takes care of everything */
791
792         if (lstat (filename, &dbuf) < 0)
793             return 0;
794
795         if (dbuf.st_ino == sbuf.st_ino)
796         {
797             if(mode)
798                 tmpStr = GETMESSAGE(3,19,"Cannot move folder into itself. %s");
799             else
800                 tmpStr = GETMESSAGE(3,20,"Cannot copy folder into itself. %s");
801             msg = XtMalloc(strlen(tmpStr)+strlen(dpth)+1);
802             sprintf(msg,tmpStr,dpth);
803             _DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
804                               CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
805
806             XtFree(msg);
807             return(1);
808         }
809
810         (void) strcat (filename, "/..");
811     }
812
813     return(0);
814 }