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) && !defined(__linux__)
69 #if defined(__linux__)
71 #include <linux/magic.h>
81 #include <Dt/Connect.h>
82 #include <Dt/DtNlUtils.h>
83 #include <Dt/SharedProcs.h>
85 #include "sharedFuncs.h"
90 /************************************************************************
91 * Bitmap Data for Default Symbol
92 **********************************<->***********************************/
94 static unsigned char errorBits[] = {
95 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0xf0, 0x3a, 0x00, 0x58, 0x55, 0x00,
96 0x2c, 0xa0, 0x00, 0x56, 0x40, 0x01, 0xaa, 0x80, 0x02, 0x46, 0x81, 0x01,
97 0x8a, 0x82, 0x02, 0x06, 0x85, 0x01, 0x0a, 0x8a, 0x02, 0x06, 0x94, 0x01,
98 0x0a, 0xe8, 0x02, 0x14, 0x50, 0x01, 0x28, 0xb0, 0x00, 0xd0, 0x5f, 0x00,
99 0xa0, 0x2a, 0x00, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
101 static unsigned char infoBits[] = {
102 0x00, 0x00, 0x78, 0x00, 0x54, 0x00, 0x2c, 0x00, 0x54, 0x00, 0x28, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x2a, 0x00, 0x5c, 0x00, 0x28, 0x00,
104 0x58, 0x00, 0x28, 0x00, 0x58, 0x00, 0x28, 0x00, 0x58, 0x00, 0x28, 0x00,
105 0x58, 0x00, 0xae, 0x01, 0x56, 0x01, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00};
107 static unsigned char questionBits[] = {
108 0xf0, 0x3f, 0x00, 0x58, 0x55, 0x00, 0xac, 0xaa, 0x00, 0xd6, 0x5f, 0x01,
109 0xea, 0xbf, 0x02, 0xf6, 0x7f, 0x01, 0xea, 0xba, 0x02, 0xf6, 0x7d, 0x05,
110 0xea, 0xba, 0x0a, 0x56, 0x7d, 0x15, 0xaa, 0xbe, 0x1e, 0x56, 0x5f, 0x01,
111 0xac, 0xaf, 0x02, 0x58, 0x57, 0x01, 0xb0, 0xaf, 0x00, 0x60, 0x55, 0x01,
112 0xa0, 0xaa, 0x00, 0x60, 0x17, 0x00, 0xa0, 0x2f, 0x00, 0x60, 0x17, 0x00,
113 0xb0, 0x2a, 0x00, 0x50, 0x55, 0x00};
115 static unsigned char warningBits[] = {
116 0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x56, 0x00, 0x2a, 0x00, 0x56, 0x00,
117 0x2a, 0x00, 0x56, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x2c, 0x00, 0x14, 0x00,
118 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x14, 0x00,
119 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00};
121 static unsigned char workingBits[] = {
122 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xaa, 0xaa, 0x0a, 0x44, 0x55, 0x06,
123 0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06, 0xcc, 0x2a, 0x02, 0x84, 0x15, 0x06,
124 0x8c, 0x2a, 0x02, 0x04, 0x15, 0x06, 0x0c, 0x0a, 0x02, 0x04, 0x06, 0x06,
125 0x0c, 0x0b, 0x02, 0x84, 0x15, 0x06, 0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06,
126 0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06, 0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06,
127 0xfe, 0xff, 0x0f, 0x56, 0x55, 0x05, 0x00, 0x00, 0x00};
130 int G_dialog_closed = FALSE;
132 /*----------------------------------------------------------
136 * Given a path, return a pointer to the directory (folder)
137 * and file (object). On error, both will be set to empty
140 * The calling routine is responsible for allocating space
141 * for object and folder.
143 * This function simply searches for the last slash (/) in
144 * the path and returns the characters preceding the slash
145 * as folder and the characters after the last slash as
146 * object. Thus, object could be a directory/folder or a
149 * There is a complimentary function, build_path, to put
150 * object and folder back together to form a path.
152 *-----------------------------------------------------------*/
155 split_path(const String path, String folder, String object)
161 if ( (lastSlash = strrchr(path,'/')) != NULL)
163 strcpy(object,lastSlash+1);
164 if(lastSlash == path) /* Must be root Folder */
175 folder[0] = object[0] = '\0';
177 } /* end split_path */
182 char *rpath, tmppath[MAX_PATH];
183 char * _DtCopyPathFromInput();
184 if (!getcwd(tmppath,MAX_PATH))
186 rpath = _DtCopyPathFromInput(path,tmppath);
190 /*-----------------------------------------------------------------
194 * Given a directory (folder) and file (object), build a string
195 * with the complete path and return it.
197 * The calling routine is responsible for freeing storage used
198 * for the returned string.
200 * There is a complimentary function, split_path, to take
201 * path apart to form folder and object
203 *-----------------------------------------------------------------*/
206 build_path(const String folder, const String object)
212 strncpy(s, folder, MAX_PATH);
213 strncat(s, "/", MAX_PATH-strlen(s));
214 strncat(s, object, MAX_PATH-strlen(s));
215 path = (String) malloc(strlen(s)+1);
220 } /* end build_path */
224 /*--------------------------------------------------------------
228 * Given a path, generate a new file name and rename the file.
230 * The rc from the system call is returned and errno is set.
232 *--------------------------------------------------------------*/
235 auto_rename(const String path)
238 char newPath[MAX_PATH];
240 generate_NewPath(newPath,path);
242 return (rename(path,newPath));
244 } /* end auto_rename */
247 /*-----------------------------------------------------------------------
251 * Given a path (and a complete path is required), append a
252 * sequence number to generate a new file name. The new file
253 * will not exist. The sequence number consists of a one-character
254 * delimiter and an integer. The function will start with
255 * 1, if the file with 1 exists it will continue to 2, etc.
256 * newPath and oldPath can point to the same area. The sequence number
257 * is appended to the end of the name unless it contains a
258 * dot, in which case the sequence number precedes the dot. For example,
259 * /cde/dtfile/dtcopy/overwrtdialog.c becomes
260 * /cde/dtfile/dtcopy/overwrtdialog~1.c. However, if the dot
261 * is the first character in the file name, the sequence number is
262 * appended, (e.g. .profile --> .profile~1).
264 *-----------------------------------------------------------------------*/
267 generate_NewPath(String newPath, String oldPath)
271 const char delim = '_';
274 String lastDot, lastSlash;
275 char firstPart[MAX_PATH], lastPart[MAX_PATH];
280 lastDot = strrchr(oldPath,'.');
281 lastSlash = strrchr(oldPath,'/');
282 if (lastSlash == NULL)
283 lastSlash = oldPath - 1; /* allows for no path and first char is dot */
284 len = lastDot - oldPath;
285 if ( lastDot != NULL && /* no dot */
286 lastDot > lastSlash+1 && /* dot is in filename, not directory name */
287 len != strlen(oldPath)-1 ) /* dot is not last character of filename */
289 /* sequence number will be inserted before filename suffix */
290 memcpy(firstPart,oldPath,len);
291 firstPart[len] = '\0';
292 strcpy(lastPart,lastDot);
296 /* sequence number will be appended to filename */
297 strcpy(firstPart,oldPath);
305 sprintf(newPath,"%s%c%d%s",firstPart,delim,i,lastPart);
306 } while (lstat(newPath,&buf) == 0);
311 } /* end generate_NewPath */
314 /****************************************************************
315 * Create a default images for symbol... used in ClassInitialize.
323 unsigned int height )
327 image = XCreateImage(display,
328 DefaultVisual(display, DefaultScreen(display)),
329 1, XYBitmap, 0, bits, width, height, 8,
331 image->byte_order = LSBFirst;
332 image->bitmap_unit = 8;
333 image->bitmap_bit_order = LSBFirst;
336 } /* end CreateDefaultImage */
341 ImageInitialize( Display *display )
345 /* create and install the default images for the symbol */
347 image = CreateDefaultImage (display, (char *)errorBits, 20, 20);
348 XmInstallImage (image, "default_xm_error");
350 image = CreateDefaultImage (display, (char *)infoBits, 11, 24);
351 XmInstallImage (image, "default_xm_information");
353 image = CreateDefaultImage (display, (char *)questionBits, 22, 22);
354 XmInstallImage (image, "default_xm_question");
356 image = CreateDefaultImage (display, (char *)warningBits, 9, 22);
357 XmInstallImage (image, "default_xm_warning");
359 image = CreateDefaultImage (display, (char *)workingBits, 21, 23);
360 XmInstallImage (image, "default_xm_working");
363 } /* end ImageInitialize */
366 CopyCheckDeletePermissionRecur(
367 char *destinationPath)
375 DPRINTF(("CheckDeletePermissionRecur(\"%s\")\n", destinationPath));
377 if (lstat(destinationPath, &statbuf) < 0)
378 return -1; /* probably does not exist */
380 if (! S_ISDIR(statbuf.st_mode))
382 if(access(destinationPath,04) < 0)
384 return 0; /* no need to check anything more */
387 dirp = opendir (destinationPath);
389 return -1; /* could not read directory */
394 while (dp = readdir (dirp))
396 if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
400 /* check for write permission in this directory */
401 if (access(destinationPath, 04|02|01) < 0)
407 /* append a '/' to the end of directory name */
408 fnamep = destinationPath + strlen(destinationPath);
414 /* append file name to end of directory name */
415 strcpy(fnamep, dp->d_name);
417 /* recursively check permission on this file */
418 if (CopyCheckDeletePermissionRecur(destinationPath))
431 CopyCheckDeletePermission(
433 char *destinationPath)
435 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)
436 struct statfs statbuf;
437 #elif defined(__NetBSD__)
438 struct statvfs statbuf;
442 char fname[PATH_MAX];
444 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)
445 if (statfs(parentdir,&statbuf) < 0) /* does not exist */
446 #elif defined(__NetBSD__)
447 if (statvfs(parentdir,&statbuf) < 0) /* does not exist */
449 if (lstat(parentdir,&statbuf) < 0) /* does not exist */
453 /* check if we are root */
456 /* if NFS, need to check if server trusts root */
457 #if defined(CSRG_BASED)
458 if (!strcmp(statbuf.f_fstypename, "nfs")) /* Root user and nfs */
459 #elif defined(__linux__)
460 if (statbuf.f_type == NFS_SUPER_MAGIC)
462 /* nothing - always check if root */
467 tmpfile = tempnam(parentdir,"dtfile");
470 /* Create a temporary file */
471 if ( (rv = creat(tmpfile,O_RDONLY)) < 0)
477 /* Delete the created file */
478 if (remove(tmpfile) < 0)
490 /* root user can delete anything */
494 /* check for read/write and execute permission on parent dir */
495 if (access(parentdir, R_OK | W_OK | X_OK) < 0)
498 /* copy destinationPath to tmp buffer */
499 strcpy(fname, destinationPath);
501 return CopyCheckDeletePermissionRecur(fname);
510 XtDestroyWidget((Widget)G_toplevel);
516 XtAppContext app_context,
522 if(checkPerms && move)
524 char title[200],*msg,*tmpmsg;
525 char *tmpstring = strdup(source_name),*tmpptr;
530 tmpptr = strrchr(tmpstring,'/');
531 if(!tmpstring || !tmpptr) /* Error */
535 if(tmpptr == tmpstring)
542 perm_status = CopyCheckDeletePermission(tmpptr,source_name);
546 if(!perm_status) /* Everything is fine just return */
553 strcpy(title,GETMESSAGE(4,7,"Object Trash - Error"));
554 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.");
556 msg = XtMalloc(strlen(tmpmsg)+strlen(source_name)+2);
557 sprintf(msg,tmpmsg,source_name);
558 _DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
559 CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
561 XtAppAddTimeOut(app_context, delay, TimeoutHandler, NULL);
564 /* wait for user to close the dialog before exiting */
566 while (!G_dialog_closed)
568 XtAppNextEvent(app_context, &event);
569 XtDispatchEvent(&event);
575 TimeoutHandler(XtPointer client_data, XtIntervalId *id)
581 * This is a generic function for resolving a cannonical path from user input.
585 _DtCopyPathFromInput(char *input_string, char *current_dir)
588 char *tmp_path = NULL;
590 char *_DtCopyChangeTildeToHome();
592 /* find relative path */
594 tmp_path = path = XtNewString(input_string);
597 /* Strip any spaces from name -- input is overwritten */
598 path = (char *) _DtStripSpaces(path);
600 /* Resolve, if there're any, environement variables */
603 char command[MAX_PATH];
605 sprintf(command,"echo %s",path);
606 if((pfp=popen(command,"r")) == NULL)
612 if (fscanf(pfp,"%s",command) >= 1)
615 path = XtNewString(command);
627 /* Resolve '~' -- new memory is allocated, old memory is freed */
629 path = _DtCopyChangeTildeToHome(path);
631 /* If current dir provided, check for relative path */
632 if (path && current_dir)
636 /* file is relative path i.e. xyz/abc */
637 if (strcmp(current_dir, "/") == 0)
639 tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 1);
640 sprintf(tmp_path, "%s%s", current_dir, path);
644 tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 2);
645 sprintf(tmp_path, "%s/%s", current_dir, path);
659 /* Resolve '.' or '..' -- input is overwritten, output may be NULL! */
660 /* Save pointer to path to free if output is NULL. */
662 path = (char *) XeEliminateDots(path);
664 /* Strip off trailing '/' */
665 dir_len = strlen(path);
666 if (dir_len > 1 && *(path + dir_len - 1) == '/')
667 *(path + dir_len - 1) = '\0';
672 _DtCopyChangeTildeToHome (input_string)
675 _DtCopyChangeTildeToHome (
681 struct passwd * pwInfo;
682 char * homedir = (char *) XtNewString(getenv("HOME"));
684 if ((input_string[1] != '/'))
688 /* ~user or ~user/path format */
690 /* is there a path? */
691 path = (char *) DtStrchr(input_string, '/');
696 if ((pwInfo = getpwnam(input_string + 1)) == NULL)
698 /* user doesn't exist */
706 /* ~user/path format */
710 if (strcmp(pwInfo->pw_dir, "/") == 0)
712 /* We don't want to end up with double '/' in the path */
713 full_path = (char *) XtMalloc(strlen(path) + 1);
714 strcpy(full_path, path);
718 full_path = (char *) XtMalloc(strlen(pwInfo->pw_dir) +
720 sprintf(full_path, "%s%s", pwInfo->pw_dir, path);
727 full_path = XtMalloc(strlen(pwInfo->pw_dir) + 1);
728 strcpy(full_path, pwInfo->pw_dir);
731 else if (input_string[1])
735 /* NOTE: users_home_dir has trailing '/' */
736 full_path = (char *) XtMalloc(strlen(homedir) + strlen(input_string+2) + 1);
737 sprintf(full_path, "%s%s", homedir, (input_string + 2));
744 full_path = XtMalloc(strlen(homedir) + 1);
745 strcpy(full_path, homedir);
749 XtFree(input_string);
754 Check(char *spth, char *dpth, int mode)
756 struct stat sbuf, dbuf;
757 char filename [MAX_PATH];
763 if (lstat (spth, &sbuf) < 0)
765 tmpStr = (GETMESSAGE(4,9, "Cannot open %s"));
766 msg = XtMalloc(strlen(tmpStr)+strlen(filename)+1);
767 sprintf(msg,tmpStr,filename);
768 _DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
769 CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
773 (void) strcpy (filename, dpth);
775 strcpy(title,GETMESSAGE(4,5,"Object Move - Error"));
777 strcpy(title,GETMESSAGE(4,6,"Object Copy - Error"));
780 while (dbuf.st_ino != ROOTINO)
782 /* Destination may not be available, in which case we need to
783 create it, so just return as successful and the remaining
784 code takes care of everything */
786 if (lstat (filename, &dbuf) < 0)
789 if (dbuf.st_ino == sbuf.st_ino)
792 tmpStr = GETMESSAGE(3,19,"Cannot move folder into itself. %s");
794 tmpStr = GETMESSAGE(3,20,"Cannot copy folder into itself. %s");
795 msg = XtMalloc(strlen(tmpStr)+strlen(dpth)+1);
796 sprintf(msg,tmpStr,dpth);
797 _DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
798 CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
804 (void) strcat (filename, "/..");