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