558 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			558 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*
 | 
						|
 * mainloop.c
 | 
						|
 * Iterating over all the command line parameters, and matching patterns
 | 
						|
 * where needed
 | 
						|
 */
 | 
						|
 | 
						|
#include "sysincludes.h"
 | 
						|
#include "msdos.h"
 | 
						|
#include "mtools.h"
 | 
						|
#include "vfat.h"
 | 
						|
#include "fs.h"
 | 
						|
#include "mainloop.h"
 | 
						|
#include "plain_io.h"
 | 
						|
#include "file.h"
 | 
						|
 | 
						|
 | 
						|
int unix_dir_loop(Stream_t *Stream, MainParam_t *mp); 
 | 
						|
int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, 
 | 
						|
	      int follow_dir_link);
 | 
						|
 | 
						|
static int _unix_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
 | 
						|
{
 | 
						|
	unix_dir_loop(Dir, mp);
 | 
						|
	return GOT_ONE;
 | 
						|
}
 | 
						|
 | 
						|
int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, int follow_dir_link)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
	int isdir;
 | 
						|
 | 
						|
	mp->File = NULL;
 | 
						|
	mp->direntry = NULL;
 | 
						|
	mp->unixSourceName = arg;
 | 
						|
	/*	mp->dir.attr = ATTR_ARCHIVE;*/
 | 
						|
	mp->loop = _unix_loop;
 | 
						|
	if((mp->lookupflags & DO_OPEN)){
 | 
						|
		mp->File = SimpleFileOpen(0, 0, arg, O_RDONLY, 0, 0, 0, 0);
 | 
						|
		if(!mp->File){
 | 
						|
			perror(arg);
 | 
						|
#if 0
 | 
						|
			tmp = _basename(arg);
 | 
						|
			strncpy(mp->filename, tmp, VBUFSIZE);
 | 
						|
			mp->filename[VBUFSIZE-1] = '\0';
 | 
						|
#endif
 | 
						|
			return ERROR_ONE;
 | 
						|
		}
 | 
						|
		GET_DATA(mp->File, 0, 0, &isdir, 0);
 | 
						|
		if(isdir) {
 | 
						|
			struct stat buf;
 | 
						|
 | 
						|
			FREE(&mp->File);
 | 
						|
#ifdef S_ISLNK
 | 
						|
			if(!follow_dir_link &&
 | 
						|
			   lstat(arg, &buf) == 0 &&
 | 
						|
			   S_ISLNK(buf.st_mode)) {
 | 
						|
				/* skip links to directories in order to avoid
 | 
						|
				 * infinite loops */
 | 
						|
				fprintf(stderr, 
 | 
						|
					"skipping directory symlink %s\n", 
 | 
						|
					arg);
 | 
						|
				return 0;				
 | 
						|
			}
 | 
						|
#endif
 | 
						|
			if(! (mp->lookupflags & ACCEPT_DIR))
 | 
						|
				return 0;
 | 
						|
			mp->File = OpenDir(Stream, arg);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if(isdir)
 | 
						|
		ret = mp->dirCallback(0, mp);
 | 
						|
	else
 | 
						|
		ret = mp->unixcallback(mp);
 | 
						|
	FREE(&mp->File);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int isSpecial(const char *name)
 | 
						|
{
 | 
						|
	if(name[0] == '\0')
 | 
						|
		return 1;
 | 
						|
	if(!strcmp(name,"."))
 | 
						|
		return 1;
 | 
						|
	if(!strcmp(name,".."))
 | 
						|
		return 1;
 | 
						|
	return 0;			
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int checkForDot(int lookupflags, const char *name)
 | 
						|
{
 | 
						|
	return (lookupflags & NO_DOTS) && isSpecial(name);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
typedef struct lookupState_t {
 | 
						|
	Stream_t *container;
 | 
						|
	int nbContainers;
 | 
						|
	Stream_t *Dir;
 | 
						|
	int nbDirs;
 | 
						|
	const char *filename;
 | 
						|
} lookupState_t;
 | 
						|
 | 
						|
static int isUniqueTarget(const char *name)
 | 
						|
{
 | 
						|
	return name && strcmp(name, "-");
 | 
						|
}
 | 
						|
 | 
						|
static int handle_leaf(direntry_t *direntry, MainParam_t *mp,
 | 
						|
		       lookupState_t *lookupState)
 | 
						|
{
 | 
						|
	Stream_t *MyFile=0;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	if(got_signal)
 | 
						|
		return ERROR_ONE;
 | 
						|
	if(lookupState) {
 | 
						|
		/* we are looking for a "target" file */
 | 
						|
		switch(lookupState->nbDirs) {
 | 
						|
			case 0: /* no directory yet, open it */
 | 
						|
				lookupState->Dir = OpenFileByDirentry(direntry);
 | 
						|
				lookupState->nbDirs++;
 | 
						|
				/* dump the container, we have
 | 
						|
				 * better now */
 | 
						|
				FREE(&lookupState->container);
 | 
						|
				return 0;
 | 
						|
			case 1: /* we have already a directory */
 | 
						|
				FREE(&lookupState->Dir);
 | 
						|
				fprintf(stderr,"Ambigous\n");
 | 
						|
				return STOP_NOW | ERROR_ONE;
 | 
						|
			default:
 | 
						|
				return STOP_NOW | ERROR_ONE;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	mp->direntry = direntry;
 | 
						|
	if(IS_DIR(direntry)) {
 | 
						|
		if(mp->lookupflags & (DO_OPEN | DO_OPEN_DIRS))
 | 
						|
			MyFile = mp->File = OpenFileByDirentry(direntry);
 | 
						|
		ret = mp->dirCallback(direntry, mp);
 | 
						|
	} else {
 | 
						|
		if(mp->lookupflags & DO_OPEN)
 | 
						|
			MyFile = mp->File = OpenFileByDirentry(direntry);
 | 
						|
		ret = mp->callback(direntry, mp);
 | 
						|
	}
 | 
						|
	FREE(&MyFile);
 | 
						|
	if(isUniqueTarget(mp->targetName))
 | 
						|
		ret |= STOP_NOW;
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
 | 
						|
{	
 | 
						|
	Stream_t *MyFile=0;
 | 
						|
	direntry_t entry;
 | 
						|
	int ret;
 | 
						|
	int r;
 | 
						|
	
 | 
						|
	ret = 0;
 | 
						|
	r=0;
 | 
						|
	initializeDirentry(&entry, Dir);
 | 
						|
	while(!got_signal &&
 | 
						|
	      (r=vfat_lookup(&entry, filename, -1,
 | 
						|
			     mp->lookupflags, mp->shortname, 
 | 
						|
			     mp->longname)) == 0 ){
 | 
						|
		mp->File = NULL;
 | 
						|
		if(!checkForDot(mp->lookupflags,entry.name)) {
 | 
						|
			MyFile = 0;
 | 
						|
			if((mp->lookupflags & DO_OPEN) ||
 | 
						|
			   (IS_DIR(&entry) && 
 | 
						|
			    (mp->lookupflags & DO_OPEN_DIRS))) {
 | 
						|
				MyFile = mp->File = OpenFileByDirentry(&entry);
 | 
						|
			}
 | 
						|
			if(got_signal)
 | 
						|
				break;
 | 
						|
			mp->direntry = &entry;
 | 
						|
			if(IS_DIR(&entry))
 | 
						|
				ret |= mp->dirCallback(&entry,mp);
 | 
						|
			else
 | 
						|
				ret |= mp->callback(&entry, mp);
 | 
						|
			FREE(&MyFile);
 | 
						|
		}
 | 
						|
		if (fat_error(Dir))
 | 
						|
			ret |= ERROR_ONE;
 | 
						|
		if(mp->fast_quit && (ret & ERROR_ONE))
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if (r == -2)
 | 
						|
	    return ERROR_ONE;
 | 
						|
	if(got_signal)
 | 
						|
		ret |= ERROR_ONE;
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int recurs_dos_loop(MainParam_t *mp, const char *filename0, 
 | 
						|
			   const char *filename1,
 | 
						|
			   lookupState_t *lookupState)
 | 
						|
{
 | 
						|
	/* Dir is de-allocated by the same entity which allocated it */
 | 
						|
	const char *ptr;
 | 
						|
	direntry_t entry;
 | 
						|
	int length;
 | 
						|
	int lookupflags;
 | 
						|
	int ret;
 | 
						|
	int have_one;
 | 
						|
	int doing_mcwd;
 | 
						|
	int r;
 | 
						|
 | 
						|
	while(1) {
 | 
						|
		/* strip dots and // */
 | 
						|
		if(!strncmp(filename0,"./", 2)) {
 | 
						|
			filename0 += 2;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		if(!strcmp(filename0,".") && filename1) {
 | 
						|
			filename0 ++;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		if(filename0[0] == '/') {
 | 
						|
			filename0++;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		if(!filename0[0]) {
 | 
						|
			if(!filename1)
 | 
						|
				break;
 | 
						|
			filename0 = filename1;
 | 
						|
			filename1 = 0;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	if(!strncmp(filename0,"../", 3) || 
 | 
						|
	   (!strcmp(filename0, "..") && filename1)) {
 | 
						|
		/* up one level */
 | 
						|
		mp->File = getDirentry(mp->File)->Dir;
 | 
						|
		return recurs_dos_loop(mp, filename0+2, filename1, lookupState);
 | 
						|
	}
 | 
						|
 | 
						|
	doing_mcwd = !!filename1;
 | 
						|
 | 
						|
	ptr = strchr(filename0, '/');
 | 
						|
	if(!ptr) {			
 | 
						|
		length = strlen(filename0);		
 | 
						|
		ptr = filename1;
 | 
						|
		filename1 = 0;
 | 
						|
	} else {
 | 
						|
		length = ptr - filename0;
 | 
						|
		ptr++;
 | 
						|
	}
 | 
						|
	if(!ptr) {
 | 
						|
		if(mp->lookupflags & OPEN_PARENT) {
 | 
						|
			mp->targetName = filename0;
 | 
						|
			ret = handle_leaf(getDirentry(mp->File), mp, 
 | 
						|
					  lookupState);
 | 
						|
			mp->targetName = 0;
 | 
						|
			return ret;
 | 
						|
		}
 | 
						|
		
 | 
						|
		if(!strcmp(filename0, ".") || !filename0[0]) {
 | 
						|
			return handle_leaf(getDirentry(mp->File), 
 | 
						|
					   mp, lookupState);
 | 
						|
		}
 | 
						|
 | 
						|
		if(!strcmp(filename0, "..")) {
 | 
						|
			return handle_leaf(getParent(getDirentry(mp->File)), mp,
 | 
						|
					   lookupState);
 | 
						|
		}
 | 
						|
 | 
						|
		lookupflags = mp->lookupflags;
 | 
						|
		
 | 
						|
		if(lookupState) {
 | 
						|
			lookupState->filename = filename0;
 | 
						|
			if(lookupState->nbContainers + lookupState->nbDirs > 0){
 | 
						|
				/* we have already one target, don't bother 
 | 
						|
				 * with this one. */
 | 
						|
				FREE(&lookupState->container);
 | 
						|
			} else {
 | 
						|
				/* no match yet.  Remember this container for 
 | 
						|
				 * later use */
 | 
						|
				lookupState->container = COPY(mp->File);
 | 
						|
			}
 | 
						|
			lookupState->nbContainers++;
 | 
						|
		}
 | 
						|
	} else
 | 
						|
		lookupflags = ACCEPT_DIR | DO_OPEN | NO_DOTS;
 | 
						|
 | 
						|
	ret = 0;
 | 
						|
	r = 0;
 | 
						|
	have_one = 0;
 | 
						|
	initializeDirentry(&entry, mp->File);
 | 
						|
	while(!(ret & STOP_NOW) &&
 | 
						|
	      !got_signal &&
 | 
						|
	      (r=vfat_lookup(&entry, filename0, length,
 | 
						|
			     lookupflags | NO_MSG, 
 | 
						|
			     mp->shortname, mp->longname)) == 0 ){
 | 
						|
		if(checkForDot(lookupflags, entry.name))
 | 
						|
			/* while following the path, ignore the
 | 
						|
			 * special entries if they were not
 | 
						|
			 * explicitly given */
 | 
						|
			continue;
 | 
						|
		have_one = 1;
 | 
						|
		if(ptr) {
 | 
						|
			Stream_t *SubDir;
 | 
						|
			SubDir = mp->File = OpenFileByDirentry(&entry);
 | 
						|
			ret |= recurs_dos_loop(mp, ptr, filename1, lookupState);
 | 
						|
			FREE(&SubDir);
 | 
						|
		} else {
 | 
						|
			ret |= handle_leaf(&entry, mp, lookupState);
 | 
						|
			if(isUniqueTarget(mp->targetName))
 | 
						|
				return ret | STOP_NOW;
 | 
						|
		}
 | 
						|
		if(doing_mcwd)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if (r == -2)
 | 
						|
		return ERROR_ONE;
 | 
						|
	if(got_signal)
 | 
						|
		return ret | ERROR_ONE;
 | 
						|
	if(doing_mcwd & !have_one)
 | 
						|
		return NO_CWD;
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int common_dos_loop(MainParam_t *mp, const char *pathname,
 | 
						|
			   lookupState_t *lookupState, int open_mode)
 | 
						|
 | 
						|
{
 | 
						|
	Stream_t *RootDir;
 | 
						|
	char *cwd;
 | 
						|
	char *drive;
 | 
						|
	char *rest;
 | 
						|
 | 
						|
	int ret;
 | 
						|
	mp->loop = _dos_loop;
 | 
						|
	
 | 
						|
	drive='\0';
 | 
						|
	cwd = "";
 | 
						|
	if((rest = skip_drive(pathname)) > pathname) {
 | 
						|
		drive = get_drive(pathname, NULL);
 | 
						|
		if (strncmp(pathname, mp->mcwd, rest - pathname) == 0)
 | 
						|
			cwd = skip_drive(mp->mcwd);
 | 
						|
		pathname = rest;
 | 
						|
	} else {
 | 
						|
		drive = get_drive(mp->mcwd, NULL);
 | 
						|
		cwd = skip_drive(mp->mcwd);
 | 
						|
	}
 | 
						|
 | 
						|
	if(*pathname=='/') /* absolute path name */
 | 
						|
		cwd = "";
 | 
						|
 | 
						|
	RootDir = mp->File = open_root_dir(drive, open_mode);
 | 
						|
	if(!mp->File)
 | 
						|
		return ERROR_ONE;
 | 
						|
 | 
						|
	ret = recurs_dos_loop(mp, cwd, pathname, lookupState);
 | 
						|
	if(ret & NO_CWD) {
 | 
						|
		/* no CWD */
 | 
						|
		*mp->mcwd = '\0';
 | 
						|
		unlink_mcwd();
 | 
						|
		ret = recurs_dos_loop(mp, "", pathname, lookupState);
 | 
						|
	}
 | 
						|
	FREE(&RootDir);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int dos_loop(MainParam_t *mp, const char *arg)
 | 
						|
{
 | 
						|
	return common_dos_loop(mp, arg, 0, mp->openflags);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int dos_target_lookup(MainParam_t *mp, const char *arg)
 | 
						|
{
 | 
						|
	lookupState_t lookupState;
 | 
						|
	int ret;
 | 
						|
	int lookupflags;
 | 
						|
 | 
						|
	lookupState.nbDirs = 0;
 | 
						|
	lookupState.Dir = 0;
 | 
						|
	lookupState.nbContainers = 0;
 | 
						|
	lookupState.container = 0;
 | 
						|
 | 
						|
	lookupflags = mp->lookupflags;
 | 
						|
	mp->lookupflags = DO_OPEN | ACCEPT_DIR;
 | 
						|
	ret = common_dos_loop(mp, arg, &lookupState, O_RDWR);
 | 
						|
	mp->lookupflags = lookupflags;
 | 
						|
	if(ret & ERROR_ONE)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	if(lookupState.nbDirs) {
 | 
						|
		mp->targetName = 0;
 | 
						|
		mp->targetDir = lookupState.Dir;
 | 
						|
		FREE(&lookupState.container); /* container no longer needed */
 | 
						|
		return ret;
 | 
						|
	}
 | 
						|
 | 
						|
	switch(lookupState.nbContainers) {
 | 
						|
		case 0:
 | 
						|
			/* no match */
 | 
						|
			fprintf(stderr,"%s: no match for target\n", arg);
 | 
						|
			return MISSED_ONE;
 | 
						|
		case 1:
 | 
						|
			mp->targetName = strdup(lookupState.filename);
 | 
						|
			mp->targetDir = lookupState.container;
 | 
						|
			return ret;
 | 
						|
		default:
 | 
						|
			/* too much */
 | 
						|
			fprintf(stderr, "Ambigous %s\n", arg);
 | 
						|
			return ERROR_ONE;			
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int unix_target_lookup(MainParam_t *mp, const char *arg)
 | 
						|
{
 | 
						|
	char *ptr;
 | 
						|
	mp->unixTarget = strdup(arg);
 | 
						|
	/* try complete filename */
 | 
						|
	if(access(mp->unixTarget, F_OK) == 0)
 | 
						|
		return GOT_ONE;
 | 
						|
	ptr = strrchr(mp->unixTarget, '/');
 | 
						|
	if(!ptr) {
 | 
						|
		mp->targetName = mp->unixTarget;
 | 
						|
		mp->unixTarget = strdup(".");
 | 
						|
		return GOT_ONE;
 | 
						|
	} else {
 | 
						|
		*ptr = '\0';
 | 
						|
		mp->targetName = ptr+1;
 | 
						|
		return GOT_ONE;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int target_lookup(MainParam_t *mp, const char *arg)
 | 
						|
{
 | 
						|
	if((mp->lookupflags & NO_UNIX) || skip_drive(arg) > arg)
 | 
						|
		return dos_target_lookup(mp, arg);
 | 
						|
	else
 | 
						|
		return unix_target_lookup(mp, arg);
 | 
						|
}
 | 
						|
 | 
						|
int main_loop(MainParam_t *mp, char **argv, int argc)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	int ret, Bret;
 | 
						|
	
 | 
						|
	Bret = 0;
 | 
						|
 | 
						|
	if(argc != 1 && mp->targetName) {
 | 
						|
		fprintf(stderr,
 | 
						|
			"Several file names given, but last argument (%s) not a directory\n", mp->targetName);
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < argc; i++) {
 | 
						|
		if ( got_signal )
 | 
						|
			break;
 | 
						|
		mp->originalArg = argv[i];
 | 
						|
		mp->basenameHasWildcard = strpbrk(_basename(mp->originalArg), 
 | 
						|
						  "*[?") != 0;
 | 
						|
		if (mp->unixcallback && skip_drive(argv[i]) == argv[i])
 | 
						|
			ret = unix_loop(0, mp, argv[i], 1);
 | 
						|
		else
 | 
						|
			ret = dos_loop(mp, argv[i]);
 | 
						|
		
 | 
						|
		if (! (ret & (GOT_ONE | ERROR_ONE)) ) {
 | 
						|
			/* one argument was unmatched */
 | 
						|
			fprintf(stderr, "%s: File \"%s\" not found\n",
 | 
						|
				progname, argv[i]);
 | 
						|
			ret |= ERROR_ONE;
 | 
						|
		}
 | 
						|
		Bret |= ret;
 | 
						|
		if(mp->fast_quit && (Bret & (MISSED_ONE | ERROR_ONE)))
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	FREE(&mp->targetDir);
 | 
						|
	if(Bret & ERROR_ONE)
 | 
						|
		return 1;
 | 
						|
	if ((Bret & GOT_ONE) && ( Bret & MISSED_ONE))
 | 
						|
		return 2;
 | 
						|
	if (Bret & MISSED_ONE)
 | 
						|
		return 1;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int dispatchToFile(direntry_t *entry, MainParam_t *mp)
 | 
						|
{
 | 
						|
	if(entry)
 | 
						|
		return mp->callback(entry, mp);
 | 
						|
	else
 | 
						|
		return mp->unixcallback(mp);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void init_mp(MainParam_t *mp)
 | 
						|
{
 | 
						|
	fix_mcwd(mp->mcwd);
 | 
						|
	mp->openflags = 0;
 | 
						|
	mp->targetName = 0;
 | 
						|
	mp->targetDir = 0;
 | 
						|
	mp->unixTarget = 0;
 | 
						|
	mp->dirCallback = dispatchToFile;
 | 
						|
	mp->unixcallback = NULL;
 | 
						|
	mp->shortname = mp->longname = 0;
 | 
						|
	mp->File = 0;
 | 
						|
	mp->fast_quit = 0;
 | 
						|
}
 | 
						|
 | 
						|
const char *mpGetBasename(MainParam_t *mp)
 | 
						|
{
 | 
						|
	if(mp->direntry)
 | 
						|
		return mp->direntry->name;
 | 
						|
	else
 | 
						|
		return _basename(mp->unixSourceName);
 | 
						|
}
 | 
						|
 | 
						|
void mpPrintFilename(FILE *fp, MainParam_t *mp)
 | 
						|
{
 | 
						|
	if(mp->direntry)
 | 
						|
		fprintPwd(fp, mp->direntry, 0);
 | 
						|
	else
 | 
						|
		fprintf(fp,"%s",mp->originalArg);
 | 
						|
}
 | 
						|
 | 
						|
const char *mpPickTargetName(MainParam_t *mp)
 | 
						|
{
 | 
						|
	/* picks the target name: either the one explicitly given by the
 | 
						|
	 * user, or the same as the source */
 | 
						|
	if(mp->targetName)
 | 
						|
		return mp->targetName;
 | 
						|
	else
 | 
						|
		return mpGetBasename(mp);
 | 
						|
}
 | 
						|
 | 
						|
char *mpBuildUnixFilename(MainParam_t *mp)
 | 
						|
{
 | 
						|
	const char *target;
 | 
						|
	char *ret;
 | 
						|
 | 
						|
	target = mpPickTargetName(mp);
 | 
						|
	ret = malloc(strlen(mp->unixTarget) + 2 + strlen(target));
 | 
						|
	if(!ret)
 | 
						|
		return 0;
 | 
						|
	strcpy(ret, mp->unixTarget);
 | 
						|
	if(*target) {
 | 
						|
#if 1 /* fix for 'mcopy -n x:file existingfile' -- H. Lermen 980816 */
 | 
						|
		if(!mp->targetName && !mp->targetDir) {
 | 
						|
			struct stat buf;
 | 
						|
			if (!stat(ret, &buf) && !S_ISDIR(buf.st_mode))
 | 
						|
				return ret;
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		strcat(ret, "/");
 | 
						|
		strcat(ret, target);
 | 
						|
	}
 | 
						|
	return ret;
 | 
						|
}
 |