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