2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $TOG: sharedFuncs.c /main/9 1998/04/06 13:15:57 mgreess $ */
24 /************************************<+>*************************************
25 ****************************************************************************
30 * DESCRIPTION: Common functions for both dtfile and dtfile_copy
32 * FUNCTIONS: CreateDefaultImage
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.
44 ****************************************************************************
45 ************************************<+>*************************************/
48 # include <sys/fs/ufs_fs.h>
49 # define ROOTINO UFSROOTINO
52 #if defined(linux) || defined(CSRG_BASED)
53 # include <sys/param.h>
62 #include <sys/types.h>
63 #include <sys/mount.h>
66 #if !defined(CSRG_BASED)
77 #include <Dt/Connect.h>
78 #include <Dt/DtNlUtils.h>
79 #include <Dt/SharedProcs.h>
81 #include "sharedFuncs.h"
86 /************************************************************************
87 * Bitmap Data for Default Symbol
88 **********************************<->***********************************/
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};
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};
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};
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};
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};
126 int G_dialog_closed = FALSE;
128 /*----------------------------------------------------------
132 * Given a path, return a pointer to the directory (folder)
133 * and file (object). On error, both will be set to empty
136 * The calling routine is responsible for allocating space
137 * for object and folder.
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
145 * There is a complimentary function, build_path, to put
146 * object and folder back together to form a path.
148 *-----------------------------------------------------------*/
151 split_path(const String path, String folder, String object)
157 if ( (lastSlash = strrchr(path,'/')) != NULL)
159 strcpy(object,lastSlash+1);
160 if(lastSlash == path) /* Must be root Folder */
171 folder[0] = object[0] = '\0';
173 } /* end split_path */
178 char *rpath, tmppath[MAX_PATH];
179 char * _DtCopyPathFromInput();
180 if (!getcwd(tmppath,MAX_PATH))
182 rpath = _DtCopyPathFromInput(path,tmppath);
186 /*-----------------------------------------------------------------
190 * Given a directory (folder) and file (object), build a string
191 * with the complete path and return it.
193 * The calling routine is responsible for freeing storage used
194 * for the returned string.
196 * There is a complimentary function, split_path, to take
197 * path apart to form folder and object
199 *-----------------------------------------------------------------*/
202 build_path(const String folder, const String object)
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);
216 } /* end build_path */
220 /*--------------------------------------------------------------
224 * Given a path, generate a new file name and rename the file.
226 * The rc from the system call is returned and errno is set.
228 *--------------------------------------------------------------*/
231 auto_rename(const String path)
234 char newPath[MAX_PATH];
236 generate_NewPath(newPath,path);
238 return (rename(path,newPath));
240 } /* end auto_rename */
243 /*-----------------------------------------------------------------------
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).
260 *-----------------------------------------------------------------------*/
263 generate_NewPath(String newPath, String oldPath)
267 const char delim = '_';
270 String lastDot, lastSlash;
271 char firstPart[MAX_PATH], lastPart[MAX_PATH];
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 */
285 /* sequence number will be inserted before filename suffix */
286 memcpy(firstPart,oldPath,len);
287 firstPart[len] = '\0';
288 strcpy(lastPart,lastDot);
292 /* sequence number will be appended to filename */
293 strcpy(firstPart,oldPath);
301 sprintf(newPath,"%s%c%d%s",firstPart,delim,i,lastPart);
302 } while (lstat(newPath,&buf) == 0);
307 } /* end generate_NewPath */
310 /****************************************************************
311 * Create a default images for symbol... used in ClassInitialize.
319 unsigned int height )
323 image = XCreateImage(display,
324 DefaultVisual(display, DefaultScreen(display)),
325 1, XYBitmap, 0, bits, width, height, 8,
327 image->byte_order = LSBFirst;
328 image->bitmap_unit = 8;
329 image->bitmap_bit_order = LSBFirst;
332 } /* end CreateDefaultImage */
337 ImageInitialize( Display *display )
341 /* create and install the default images for the symbol */
343 image = CreateDefaultImage (display, (char *)errorBits, 20, 20);
344 XmInstallImage (image, "default_xm_error");
346 image = CreateDefaultImage (display, (char *)infoBits, 11, 24);
347 XmInstallImage (image, "default_xm_information");
349 image = CreateDefaultImage (display, (char *)questionBits, 22, 22);
350 XmInstallImage (image, "default_xm_question");
352 image = CreateDefaultImage (display, (char *)warningBits, 9, 22);
353 XmInstallImage (image, "default_xm_warning");
355 image = CreateDefaultImage (display, (char *)workingBits, 21, 23);
356 XmInstallImage (image, "default_xm_working");
359 } /* end ImageInitialize */
361 #if !defined(CSRG_BASED)
367 if(ustat(dev,&u1) < 0)
374 CopyCheckDeletePermissionRecur(
375 char *destinationPath)
383 DPRINTF(("CheckDeletePermissionRecur(\"%s\")\n", destinationPath));
385 if (lstat(destinationPath, &statbuf) < 0)
386 return -1; /* probably does not exist */
388 if (! S_ISDIR(statbuf.st_mode))
390 if(access(destinationPath,04) < 0)
392 return 0; /* no need to check anything more */
395 dirp = opendir (destinationPath);
397 return -1; /* could not read directory */
402 while (dp = readdir (dirp))
404 if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
408 /* check for write permission in this directory */
409 if (access(destinationPath, 04|02|01) < 0)
415 /* append a '/' to the end of directory name */
416 fnamep = destinationPath + strlen(destinationPath);
422 /* append file name to end of directory name */
423 strcpy(fnamep, dp->d_name);
425 /* recursively check permission on this file */
426 if (CopyCheckDeletePermissionRecur(destinationPath))
439 CopyCheckDeletePermission(
441 char *destinationPath)
443 #if defined(__FreeBSD__) || defined(__OpenBSD__)
444 struct statfs statbuf;
445 #elif defined(__NetBSD__)
446 struct statvfs statbuf;
450 char fname[PATH_MAX];
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 */
457 if (lstat(parentdir,&statbuf) < 0) /* does not exist */
461 /* check if we are root */
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 */
468 if (CopyFileSysType(statbuf.st_dev) < 0) /* Root user and nfs */
473 tmpfile = tempnam(parentdir,"dtfile");
476 /* Create a temporary file */
477 if ( (rv = creat(tmpfile,O_RDONLY)) < 0)
483 /* Delete the created file */
484 if (remove(tmpfile) < 0)
496 /* root user can delete anything */
500 /* check for read/write and execute permission on parent dir */
501 if (access(parentdir, R_OK | W_OK | X_OK) < 0)
504 /* copy destinationPath to tmp buffer */
505 strcpy(fname, destinationPath);
507 return CopyCheckDeletePermissionRecur(fname);
516 XtDestroyWidget((Widget)G_toplevel);
522 XtAppContext app_context,
528 if(checkPerms && move)
530 char title[200],*msg,*tmpmsg;
531 char *tmpstring = strdup(source_name),*tmpptr;
536 tmpptr = strrchr(tmpstring,'/');
537 if(!tmpstring || !tmpptr) /* Error */
541 if(tmpptr == tmpstring)
548 perm_status = CopyCheckDeletePermission(tmpptr,source_name);
552 if(!perm_status) /* Everything is fine just return */
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.");
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);
567 XtAppAddTimeOut(app_context, delay, TimeoutHandler, NULL);
570 /* wait for user to close the dialog before exiting */
572 while (!G_dialog_closed)
574 XtAppNextEvent(app_context, &event);
575 XtDispatchEvent(&event);
581 TimeoutHandler(XtPointer client_data, XtIntervalId *id)
587 * This is a generic function for resolving a cannonical path from user input.
591 _DtCopyPathFromInput(char *input_string, char *current_dir)
594 char *tmp_path = NULL;
596 char *_DtCopyChangeTildeToHome();
598 /* find relative path */
600 tmp_path = path = XtNewString(input_string);
603 /* Strip any spaces from name -- input is overwritten */
604 path = (char *) _DtStripSpaces(path);
606 /* Resolve, if there're any, environement variables */
609 char command[MAX_PATH];
611 sprintf(command,"echo %s",path);
612 if((pfp=popen(command,"r")) == NULL)
618 if (fscanf(pfp,"%s",command) >= 1)
621 path = XtNewString(command);
633 /* Resolve '~' -- new memory is allocated, old memory is freed */
635 path = _DtCopyChangeTildeToHome(path);
637 /* If current dir provided, check for relative path */
638 if (path && current_dir)
642 /* file is relative path i.e. xyz/abc */
643 if (strcmp(current_dir, "/") == 0)
645 tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 1);
646 sprintf(tmp_path, "%s%s", current_dir, path);
650 tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 2);
651 sprintf(tmp_path, "%s/%s", current_dir, path);
665 /* Resolve '.' or '..' -- input is overwritten, output may be NULL! */
666 /* Save pointer to path to free if output is NULL. */
668 path = (char *) XeEliminateDots(path);
670 /* Strip off trailing '/' */
671 dir_len = strlen(path);
672 if (dir_len > 1 && *(path + dir_len - 1) == '/')
673 *(path + dir_len - 1) = '\0';
678 _DtCopyChangeTildeToHome (input_string)
681 _DtCopyChangeTildeToHome (
687 struct passwd * pwInfo;
688 char * homedir = (char *) XtNewString(getenv("HOME"));
690 if ((input_string[1] != '/'))
694 /* ~user or ~user/path format */
696 /* is there a path? */
697 path = (char *) DtStrchr(input_string, '/');
702 if ((pwInfo = getpwnam(input_string + 1)) == NULL)
704 /* user doesn't exist */
712 /* ~user/path format */
716 if (strcmp(pwInfo->pw_dir, "/") == 0)
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);
724 full_path = (char *) XtMalloc(strlen(pwInfo->pw_dir) +
726 sprintf(full_path, "%s%s", pwInfo->pw_dir, path);
733 full_path = XtMalloc(strlen(pwInfo->pw_dir) + 1);
734 strcpy(full_path, pwInfo->pw_dir);
737 else if (input_string[1])
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));
750 full_path = XtMalloc(strlen(homedir) + 1);
751 strcpy(full_path, homedir);
755 XtFree(input_string);
760 Check(char *spth, char *dpth, int mode)
762 struct stat sbuf, dbuf;
763 char filename [MAX_PATH];
769 if (lstat (spth, &sbuf) < 0)
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);
779 (void) strcpy (filename, dpth);
781 strcpy(title,GETMESSAGE(4,5,"Object Move - Error"));
783 strcpy(title,GETMESSAGE(4,6,"Object Copy - Error"));
786 while (dbuf.st_ino != ROOTINO)
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 */
792 if (lstat (filename, &dbuf) < 0)
795 if (dbuf.st_ino == sbuf.st_ino)
798 tmpStr = GETMESSAGE(3,19,"Cannot move folder into itself. %s");
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);
810 (void) strcat (filename, "/..");