cdesktopenv/cde/programs/dtfile/dtcopy/sharedFuncs.c

784 lines
20 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $TOG: sharedFuncs.c /main/9 1998/04/06 13:15:57 mgreess $ */
/************************************<+>*************************************
****************************************************************************
*
* FILE: sharedFuncs.c
*
*
* DESCRIPTION: Common functions for both dtfile and dtfile_copy
*
* FUNCTIONS: CreateDefaultImage
* ImageInitialize
* auto_rename
* build_path
* generate_NewPath
* split_path
*
* (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
* (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
* (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
* (c) Copyright 1993, 1994, 1995 Novell, Inc.
*
****************************************************************************
************************************<+>*************************************/
#if defined(SVR4)
# include <sys/fs/ufs_fs.h>
# define ROOTINO UFSROOTINO
#endif /* SVR4 */
#if defined(__linux__) || defined(CSRG_BASED)
# include <sys/param.h>
# define ROOTINO 2
#endif
#include <string.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <pwd.h>
#include <fcntl.h>
#if !defined(CSRG_BASED) && !defined(__linux__)
#include <ustat.h>
#endif
#if defined(__linux__)
#include <sys/vfs.h>
#include <linux/magic.h>
#endif
#include <dirent.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Dt/Connect.h>
#include <Dt/DtNlUtils.h>
#include <Dt/SharedProcs.h>
#include "sharedFuncs.h"
#include "dtcopy.h"
/************************************************************************
* Bitmap Data for Default Symbol
**********************************<->***********************************/
#include <X11/bitmaps/xm_error>
#include <X11/bitmaps/xm_information>
#include <X11/bitmaps/xm_question>
#include <X11/bitmaps/xm_warning>
#include <X11/bitmaps/xm_working>
Widget G_toplevel;
int G_dialog_closed = FALSE;
/*----------------------------------------------------------
*
* split_path
*
* Given a path, return a pointer to the directory (folder)
* and file (object). On error, both will be set to empty
* strings.
*
* The calling routine is responsible for allocating space
* for object and folder.
*
* This function simply searches for the last slash (/) in
* the path and returns the characters preceding the slash
* as folder and the characters after the last slash as
* object. Thus, object could be a directory/folder or a
* file.
*
* There is a complimentary function, build_path, to put
* object and folder back together to form a path.
*
*-----------------------------------------------------------*/
void
split_path(const String path, String folder, String object)
{
String lastSlash;
if ( (lastSlash = strrchr(path,'/')) != NULL)
{
strcpy(object,lastSlash+1);
if(lastSlash == path) /* Must be root Folder */
strcpy(folder,"/");
else
{
*lastSlash = '\0';
strcpy(folder,path);
*lastSlash = '/';
}
}
else
{
folder[0] = object[0] = '\0';
}
} /* end split_path */
char *
get_path(char *path)
{
char *rpath, tmppath[MAX_PATH];
char * _DtCopyPathFromInput();
if (!getcwd(tmppath,MAX_PATH))
return NULL;
rpath = _DtCopyPathFromInput(path,tmppath);
return rpath;
}
/*-----------------------------------------------------------------
*
* build_path
*
* Given a directory (folder) and file (object), build a string
* with the complete path and return it.
*
* The calling routine is responsible for freeing storage used
* for the returned string.
*
* There is a complimentary function, split_path, to take
* path apart to form folder and object
*
*-----------------------------------------------------------------*/
String
build_path(const String folder, const String object)
{
char s[MAX_PATH];
String path;
strncpy(s, folder, MAX_PATH);
strncat(s, "/", MAX_PATH-strlen(s));
strncat(s, object, MAX_PATH-strlen(s));
path = (String) malloc(strlen(s)+1);
strcpy(path,s);
return path;
} /* end build_path */
/*--------------------------------------------------------------
*
* auto_rename
*
* Given a path, generate a new file name and rename the file.
*
* The rc from the system call is returned and errno is set.
*
*--------------------------------------------------------------*/
int
auto_rename(const String path)
{
char newPath[MAX_PATH];
generate_NewPath(newPath,path);
errno = 0;
return (rename(path,newPath));
} /* end auto_rename */
/*-----------------------------------------------------------------------
*
* generate_NewPath
*
* Given a path (and a complete path is required), append a
* sequence number to generate a new file name. The new file
* will not exist. The sequence number consists of a one-character
* delimiter and an integer. The function will start with
* 1, if the file with 1 exists it will continue to 2, etc.
* newPath and oldPath can point to the same area. The sequence number
* is appended to the end of the name unless it contains a
* dot, in which case the sequence number precedes the dot. For example,
* /cde/dtfile/dtcopy/overwrtdialog.c becomes
* /cde/dtfile/dtcopy/overwrtdialog~1.c. However, if the dot
* is the first character in the file name, the sequence number is
* appended, (e.g. .profile --> .profile~1).
*
*-----------------------------------------------------------------------*/
void
generate_NewPath(String newPath, String oldPath)
{
const char delim = '_';
struct stat buf;
String lastDot, lastSlash;
char firstPart[MAX_PATH], lastPart[MAX_PATH];
int i = 0;
int len;
lastDot = strrchr(oldPath,'.');
lastSlash = strrchr(oldPath,'/');
if (lastSlash == NULL)
lastSlash = oldPath - 1; /* allows for no path and first char is dot */
len = lastDot - oldPath;
if ( lastDot != NULL && /* no dot */
lastDot > lastSlash+1 && /* dot is in filename, not directory name */
len != strlen(oldPath)-1 ) /* dot is not last character of filename */
{
/* sequence number will be inserted before filename suffix */
memcpy(firstPart,oldPath,len);
firstPart[len] = '\0';
strcpy(lastPart,lastDot);
}
else
{
/* sequence number will be appended to filename */
strcpy(firstPart,oldPath);
lastPart[0] = '\0';
}
do
{
i++;
sprintf(newPath,"%s%c%d%s",firstPart,delim,i,lastPart);
} while (lstat(newPath,&buf) == 0);
return;
} /* end generate_NewPath */
/****************************************************************
* Create a default images for symbol... used in ClassInitialize.
****************/
XImage *
CreateDefaultImage(
Display *display,
char *bits,
unsigned int width,
unsigned int height )
{
XImage *image ;
image = XCreateImage(display,
DefaultVisual(display, DefaultScreen(display)),
1, XYBitmap, 0, bits, width, height, 8,
(width+7) >> 3);
image->byte_order = LSBFirst;
image->bitmap_unit = 8;
image->bitmap_bit_order = LSBFirst;
return( image) ;
} /* end CreateDefaultImage */
void
ImageInitialize( Display *display )
{
XImage *image;
/* create and install the default images for the symbol */
image = CreateDefaultImage (display, (char *)xm_error_bits, xm_error_width,
xm_error_height);
XmInstallImage (image, "default_xm_error");
image = CreateDefaultImage (display, (char *)xm_information_bits,
xm_information_width, xm_information_height);
XmInstallImage (image, "default_xm_information");
image = CreateDefaultImage (display, (char *)xm_question_bits,
xm_question_width, xm_question_height);
XmInstallImage (image, "default_xm_question");
image = CreateDefaultImage (display, (char *)xm_warning_bits,
xm_warning_width, xm_warning_height);
XmInstallImage (image, "default_xm_warning");
image = CreateDefaultImage (display, (char *)xm_working_bits,
xm_working_width, xm_working_height);
XmInstallImage (image, "default_xm_working");
return ;
} /* end ImageInitialize */
static int
CopyCheckDeletePermissionRecur(
char *destinationPath)
{
struct stat statbuf;
DIR *dirp;
struct dirent * dp;
Boolean first_file;
char *fnamep;
DPRINTF(("CheckDeletePermissionRecur(\"%s\")\n", destinationPath));
if (lstat(destinationPath, &statbuf) < 0)
return -1; /* probably does not exist */
if (! S_ISDIR(statbuf.st_mode))
{
if(access(destinationPath,04) < 0)
return -1;
return 0; /* no need to check anything more */
}
dirp = opendir (destinationPath);
if (dirp == NULL)
return -1; /* could not read directory */
first_file = True;
while (dp = readdir (dirp))
{
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
{
if (first_file)
{
/* check for write permission in this directory */
if (access(destinationPath, 04|02|01) < 0)
{
closedir(dirp);
return -1;
}
/* append a '/' to the end of directory name */
fnamep = destinationPath + strlen(destinationPath);
*fnamep++ = '/';
first_file = False;
}
/* append file name to end of directory name */
strcpy(fnamep, dp->d_name);
/* recursively check permission on this file */
if (CopyCheckDeletePermissionRecur(destinationPath))
{
closedir(dirp);
return -1;
}
}
}
closedir(dirp);
return 0;
}
static int
CopyCheckDeletePermission(
char *parentdir,
char *destinationPath)
{
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)
struct statfs statbuf;
#elif defined(__NetBSD__)
struct statvfs statbuf;
#else
struct stat statbuf;
#endif
char fname[PATH_MAX];
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)
if (statfs(parentdir,&statbuf) < 0) /* does not exist */
#elif defined(__NetBSD__)
if (statvfs(parentdir,&statbuf) < 0) /* does not exist */
#else
if (lstat(parentdir,&statbuf) < 0) /* does not exist */
#endif
return -1;
/* check if we are root */
if (getuid() == 0)
{
/* if NFS, need to check if server trusts root */
#if defined(CSRG_BASED)
if (!strcmp(statbuf.f_fstypename, "nfs")) /* Root user and nfs */
#elif defined(__linux__)
if (statbuf.f_type == NFS_SUPER_MAGIC)
#else
/* nothing - always check if root */
#endif
{
char *tmpfile;
int rv;
tmpfile = tempnam(parentdir,"dtfile");
if (tmpfile)
{
/* Create a temporary file */
if ( (rv = creat(tmpfile,O_RDONLY)) < 0)
{
free(tmpfile);
return -1;
}
close(rv);
/* Delete the created file */
if (remove(tmpfile) < 0)
{
free(tmpfile);
return -1;
}
free(tmpfile);
}
else
return -1;
}
/* root user can delete anything */
return 0;
}
/* check for read/write and execute permission on parent dir */
if (access(parentdir, R_OK | W_OK | X_OK) < 0)
return -1;
/* copy destinationPath to tmp buffer */
strcpy(fname, destinationPath);
return CopyCheckDeletePermissionRecur(fname);
}
void
CloseTopLevel(
Widget w,
void *client_data,
void *call_data)
{
XtDestroyWidget((Widget)G_toplevel);
exit(-1);
}
void
CheckDeleteAccess(
XtAppContext app_context,
int delay,
Boolean checkPerms,
Boolean move,
char *source_name)
{
if(checkPerms && move)
{
char title[200],*msg,*tmpmsg;
char *tmpstring = strdup(source_name),*tmpptr;
XEvent event;
int perm_status = 0;
delay = 10000;
tmpptr = strrchr(tmpstring,'/');
if(!tmpstring || !tmpptr) /* Error */
perm_status = 1;
else
{
if(tmpptr == tmpstring)
tmpptr = "/";
else
{
*tmpptr = '\0';
tmpptr = tmpstring;
}
perm_status = CopyCheckDeletePermission(tmpptr,source_name);
free(tmpstring);
tmpstring = NULL;
}
if(!perm_status) /* Everything is fine just return */
{
return;
}
free(tmpstring);
strcpy(title,GETMESSAGE(4,7,"Object Trash - Error"));
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.");
msg = XtMalloc(strlen(tmpmsg)+strlen(source_name)+2);
sprintf(msg,tmpmsg,source_name);
_DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
/*
XtAppAddTimeOut(app_context, delay, TimeoutHandler, NULL);
*/
/* wait for user to close the dialog before exiting */
XtFree(msg);
while (!G_dialog_closed)
{
XtAppNextEvent(app_context, &event);
XtDispatchEvent(&event);
}
}
}
void
TimeoutHandler(XtPointer client_data, XtIntervalId *id)
{
exit(0);
}
/*
* This is a generic function for resolving a cannonical path from user input.
*/
char *
_DtCopyPathFromInput(char *input_string, char *current_dir)
{
char *path = NULL;
char *tmp_path = NULL;
int dir_len;
char *_DtCopyChangeTildeToHome();
/* find relative path */
tmp_path = path = XtNewString(input_string);
/* Strip any spaces from name -- input is overwritten */
path = (char *) _DtStripSpaces(path);
/* Resolve, if there're any, environement variables */
{
FILE *pfp;
char command[MAX_PATH];
sprintf(command,"echo %s",path);
if((pfp=popen(command,"r")) == NULL)
{
}
else
{
if (fscanf(pfp,"%s",command) >= 1)
{
XtFree(path);
path = XtNewString(command);
}
else
path = NULL;
pclose(pfp);
}
}
if (!path)
return NULL;
/* Resolve '~' -- new memory is allocated, old memory is freed */
if (*path == '~')
path = _DtCopyChangeTildeToHome(path);
/* If current dir provided, check for relative path */
if (path && current_dir)
{
if (*path != '/')
{
/* file is relative path i.e. xyz/abc */
if (strcmp(current_dir, "/") == 0)
{
tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 1);
sprintf(tmp_path, "%s%s", current_dir, path);
}
else
{
tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 2);
sprintf(tmp_path, "%s/%s", current_dir, path);
}
XtFree(path);
path = tmp_path;
tmp_path = NULL;
}
}
else if (!path)
{
XtFree(tmp_path);
return NULL;
}
/* Resolve '.' or '..' -- input is overwritten, output may be NULL! */
/* Save pointer to path to free if output is NULL. */
tmp_path = path;
path = (char *) XeEliminateDots(path);
/* Strip off trailing '/' */
dir_len = strlen(path);
if (dir_len > 1 && *(path + dir_len - 1) == '/')
*(path + dir_len - 1) = '\0';
return path;
}
char *
#ifdef _NO_PROTO
_DtCopyChangeTildeToHome (input_string)
char *input_string;
#else
_DtCopyChangeTildeToHome (
char *input_string)
#endif
{
char *path;
char *full_path;
struct passwd * pwInfo;
char * homedir = (char *) XtNewString(getenv("HOME"));
if ((input_string[1] != '/'))
{
char *path;
/* ~user or ~user/path format */
/* is there a path? */
path = (char *) DtStrchr(input_string, '/');
/* find user */
if (path)
*path = '/';
if ((pwInfo = getpwnam(input_string + 1)) == NULL)
{
/* user doesn't exist */
if (path)
*path = '/';
return NULL;
}
if (path)
{
/* ~user/path format */
*path = '/';
if (strcmp(pwInfo->pw_dir, "/") == 0)
{
/* We don't want to end up with double '/' in the path */
full_path = (char *) XtMalloc(strlen(path) + 1);
strcpy(full_path, path);
}
else
{
full_path = (char *) XtMalloc(strlen(pwInfo->pw_dir) +
strlen(path) + 1);
sprintf(full_path, "%s%s", pwInfo->pw_dir, path);
}
}
else
{
/* ~user format */
full_path = XtMalloc(strlen(pwInfo->pw_dir) + 1);
strcpy(full_path, pwInfo->pw_dir);
}
}
else if (input_string[1])
{
/* ~/path format */
/* NOTE: users_home_dir has trailing '/' */
full_path = (char *) XtMalloc(strlen(homedir) + strlen(input_string+2) + 1);
sprintf(full_path, "%s%s", homedir, (input_string + 2));
}
else
{
/* ~ format */
full_path = XtMalloc(strlen(homedir) + 1);
strcpy(full_path, homedir);
}
XtFree(homedir);
XtFree(input_string);
return(full_path);
}
int
Check(char *spth, char *dpth, int mode)
{
struct stat sbuf, dbuf;
char filename [MAX_PATH];
char * msg;
char * tmpStr;
char title[300];
sbuf.st_ino = 0;
if (lstat (spth, &sbuf) < 0)
{
tmpStr = (GETMESSAGE(4,9, "Cannot open %s"));
msg = XtMalloc(strlen(tmpStr)+strlen(filename)+1);
sprintf(msg,tmpStr,filename);
_DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
XtFree(msg);
return 0;
}
(void) strcpy (filename, dpth);
if(mode)
strcpy(title,GETMESSAGE(4,5,"Object Move - Error"));
else
strcpy(title,GETMESSAGE(4,6,"Object Copy - Error"));
dbuf.st_ino = 0;
while (dbuf.st_ino != ROOTINO)
{
/* Destination may not be available, in which case we need to
create it, so just return as successful and the remaining
code takes care of everything */
if (lstat (filename, &dbuf) < 0)
return 0;
if (dbuf.st_ino == sbuf.st_ino)
{
if(mode)
tmpStr = GETMESSAGE(3,19,"Cannot move folder into itself. %s");
else
tmpStr = GETMESSAGE(3,20,"Cannot copy folder into itself. %s");
msg = XtMalloc(strlen(tmpStr)+strlen(dpth)+1);
sprintf(msg,tmpStr,dpth);
_DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
XtFree(msg);
return(1);
}
(void) strcat (filename, "/..");
}
return(0);
}