Path: blob/master/src/java.base/share/native/libjli/wildcard.c
67707 views
/*1* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* Class-Path Wildcards27*28* The syntax for wildcards is a single asterisk. The class path29* foo/"*", e.g., loads all jar files in the directory named foo.30* (This requires careful quotation when used in shell scripts.)31*32* Only files whose names end in .jar or .JAR are matched.33* Files whose names end in .zip, or which have a particular34* magic number, regardless of filename extension, are not35* matched.36*37* Files are considered regardless of whether or not they are38* "hidden" in the UNIX sense, i.e., have names beginning with '.'.39*40* A wildcard only matches jar files, not class files in the same41* directory. If you want to load both class files and jar files from42* a single directory foo then you can say foo:foo/"*", or foo/"*":foo43* if you want the jar files to take precedence.44*45* Subdirectories are not searched recursively, i.e., foo/"*" only46* looks for jar files in foo, not in foo/bar, foo/baz, etc.47*48* Expansion of wildcards is done early, prior to the invocation of a49* program's main method, rather than late, during the class-loading50* process itself. Each element of the input class path containing a51* wildcard is replaced by the (possibly empty) sequence of elements52* generated by enumerating the jar files in the named directory. If53* the directory foo contains a.jar, b.jar, and c.jar,54* e.g., then the class path foo/"*" is expanded into55* foo/a.jar:foo/b.jar:foo/c.jar, and that string would be the value56* of the system property java.class.path.57*58* The order in which the jar files in a directory are enumerated in59* the expanded class path is not specified and may vary from platform60* to platform and even from moment to moment on the same machine. A61* well-constructed application should not depend upon any particular62* order. If a specific order is required then the jar files can be63* enumerated explicitly in the class path.64*65* The CLASSPATH environment variable is not treated any differently66* from the -classpath (equiv. -cp) command-line option,67* i.e. wildcards are honored in all these cases.68*69* Class-path wildcards are not honored in the Class-Path jar-manifest70* header.71*72* Class-path wildcards are honored not only by the Java launcher but73* also by most other command-line tools that accept class paths, and74* in particular by javac and javadoc.75*76* Class-path wildcards are not honored in any other kind of path, and77* especially not in the bootstrap class path, which is a mere78* artifact of our implementation and not something that developers79* should use.80*81* Classpath wildcards are only expanded in the Java launcher code,82* supporting the use of wildcards on the command line and in the83* CLASSPATH environment variable. We do not support the use of84* wildcards by applications that embed the JVM.85*/8687#include <stddef.h>88#include <stdio.h>89#include <stdlib.h>90#include <string.h>91#include <sys/types.h>92#include "java.h" /* Strictly for PATH_SEPARATOR/FILE_SEPARATOR */93#include "jli_util.h"9495#ifdef _WIN3296#include <windows.h>97#else /* Unix */98#include <unistd.h>99#include <dirent.h>100#endif /* Unix */101102#if defined(_AIX)103#define DIR DIR64104#define dirent dirent64105#define opendir opendir64106#define readdir readdir64107#define closedir closedir64108#endif109110static int111exists(const char* filename)112{113#ifdef _WIN32114return _access(filename, 0) == 0;115#else116return access(filename, F_OK) == 0;117#endif118}119120#define NEW_(TYPE) ((TYPE) JLI_MemAlloc(sizeof(struct TYPE##_)))121122/*123* Wildcard directory iteration.124* WildcardIterator_for(wildcard) returns an iterator.125* Each call to that iterator's next() method returns the basename126* of an entry in the wildcard's directory. The basename's memory127* belongs to the iterator. The caller is responsible for prepending128* the directory name and file separator, if necessary.129* When done with the iterator, call the close method to clean up.130*/131typedef struct WildcardIterator_* WildcardIterator;132133#ifdef _WIN32134struct WildcardIterator_135{136HANDLE handle;137char *firstFile; /* Stupid FindFirstFile...FindNextFile */138};139// since this is used repeatedly we keep it here.140static WIN32_FIND_DATA find_data;141static WildcardIterator142WildcardIterator_for(const char *wildcard)143{144WildcardIterator it = NEW_(WildcardIterator);145HANDLE handle = FindFirstFile(wildcard, &find_data);146if (handle == INVALID_HANDLE_VALUE) {147JLI_MemFree(it);148return NULL;149}150it->handle = handle;151it->firstFile = find_data.cFileName;152return it;153}154155static char *156WildcardIterator_next(WildcardIterator it)157{158if (it->firstFile != NULL) {159char *firstFile = it->firstFile;160it->firstFile = NULL;161return firstFile;162}163return FindNextFile(it->handle, &find_data)164? find_data.cFileName : NULL;165}166167static void168WildcardIterator_close(WildcardIterator it)169{170if (it) {171FindClose(it->handle);172JLI_MemFree(it->firstFile);173JLI_MemFree(it);174}175}176177#else /* Unix */178struct WildcardIterator_179{180DIR *dir;181};182183static WildcardIterator184WildcardIterator_for(const char *wildcard)185{186DIR *dir;187int wildlen = JLI_StrLen(wildcard);188if (wildlen < 2) {189dir = opendir(".");190} else {191char *dirname = JLI_StringDup(wildcard);192dirname[wildlen - 1] = '\0';193dir = opendir(dirname);194JLI_MemFree(dirname);195}196if (dir == NULL)197return NULL;198else {199WildcardIterator it = NEW_(WildcardIterator);200it->dir = dir;201return it;202}203}204205static char *206WildcardIterator_next(WildcardIterator it)207{208struct dirent* dirp = readdir(it->dir);209return dirp ? dirp->d_name : NULL;210}211212static void213WildcardIterator_close(WildcardIterator it)214{215if (it) {216closedir(it->dir);217JLI_MemFree(it);218}219}220#endif /* Unix */221222static int223equal(const char *s1, const char *s2)224{225return JLI_StrCmp(s1, s2) == 0;226}227228static int229isJarFileName(const char *filename)230{231int len = (int)JLI_StrLen(filename);232return (len >= 4) &&233(filename[len - 4] == '.') &&234(equal(filename + len - 3, "jar") ||235equal(filename + len - 3, "JAR")) &&236/* Paranoia: Maybe filename is "DIR:foo.jar" */237(JLI_StrChr(filename, PATH_SEPARATOR) == NULL);238}239240static char *241wildcardConcat(const char *wildcard, const char *basename)242{243int wildlen = (int)JLI_StrLen(wildcard);244int baselen = (int)JLI_StrLen(basename);245char *filename = (char *) JLI_MemAlloc(wildlen + baselen);246/* Replace the trailing '*' with basename */247memcpy(filename, wildcard, wildlen-1);248memcpy(filename+wildlen-1, basename, baselen+1);249return filename;250}251252static JLI_List253wildcardFileList(const char *wildcard)254{255const char *basename;256JLI_List fl = JLI_List_new(16);257WildcardIterator it = WildcardIterator_for(wildcard);258259if (it == NULL)260{261JLI_List_free(fl);262return NULL;263}264265while ((basename = WildcardIterator_next(it)) != NULL)266if (isJarFileName(basename))267JLI_List_add(fl, wildcardConcat(wildcard, basename));268WildcardIterator_close(it);269return fl;270}271272static int273isWildcard(const char *filename)274{275int len = (int)JLI_StrLen(filename);276return (len > 0) &&277(filename[len - 1] == '*') &&278(len == 1 || IS_FILE_SEPARATOR(filename[len - 2])) &&279(! exists(filename));280}281282static int283FileList_expandWildcards(JLI_List fl)284{285size_t i, j;286int expandedCnt = 0;287for (i = 0; i < fl->size; i++) {288if (isWildcard(fl->elements[i])) {289JLI_List expanded = wildcardFileList(fl->elements[i]);290if (expanded != NULL && expanded->size > 0) {291expandedCnt++;292JLI_MemFree(fl->elements[i]);293JLI_List_ensureCapacity(fl, fl->size + expanded->size);294for (j = fl->size - 1; j >= i+1; j--)295fl->elements[j+expanded->size-1] = fl->elements[j];296for (j = 0; j < expanded->size; j++)297fl->elements[i+j] = expanded->elements[j];298i += expanded->size - 1;299fl->size += expanded->size - 1;300/* fl expropriates expanded's elements. */301expanded->size = 0;302}303JLI_List_free(expanded);304}305}306return expandedCnt;307}308309const char *310JLI_WildcardExpandClasspath(const char *classpath)311{312const char *expanded;313JLI_List fl;314315if (JLI_StrChr(classpath, '*') == NULL)316return classpath;317fl = JLI_List_split(classpath, PATH_SEPARATOR);318expanded = FileList_expandWildcards(fl) ?319JLI_List_join(fl, PATH_SEPARATOR) : classpath;320JLI_List_free(fl);321if (getenv(JLDEBUG_ENV_ENTRY) != 0)322printf("Expanded wildcards:\n"323" before: \"%s\"\n"324" after : \"%s\"\n",325classpath, expanded);326return expanded;327}328329#ifdef DEBUG_WILDCARD330static void331FileList_print(JLI_List fl)332{333size_t i;334putchar('[');335for (i = 0; i < fl->size; i++) {336if (i > 0) printf(", ");337printf("\"%s\"",fl->elements[i]);338}339putchar(']');340}341342static void343wildcardExpandArgv(const char ***argv)344{345int i;346for (i = 0; (*argv)[i]; i++) {347if (equal((*argv)[i], "-cp") ||348equal((*argv)[i], "-classpath")) {349i++;350(*argv)[i] = wildcardExpandClasspath((*argv)[i]);351}352}353}354355static void356debugPrintArgv(char *argv[])357{358int i;359putchar('[');360for (i = 0; argv[i]; i++) {361if (i > 0) printf(", ");362printf("\"%s\"", argv[i]);363}364printf("]\n");365}366367int368main(int argc, char *argv[])369{370argv[0] = "java";371wildcardExpandArgv((const char***)&argv);372debugPrintArgv(argv);373/* execvp("java", argv); */374return 0;375}376#endif /* DEBUG_WILDCARD */377378/* Cute little perl prototype implementation....379380my $sep = ($^O =~ /^(Windows|cygwin)/) ? ";" : ":";381382sub expand($) {383opendir DIR, $_[0] or return $_[0];384join $sep, map {"$_[0]/$_"} grep {/\.(jar|JAR)$/} readdir DIR;385}386387sub munge($) {388join $sep,389map {(! -r $_ and s/[\/\\]+\*$//) ? expand $_ : $_} split $sep, $_[0];390}391392for (my $i = 0; $i < @ARGV - 1; $i++) {393$ARGV[$i+1] = munge $ARGV[$i+1] if $ARGV[$i] =~ /^-c(p|lasspath)$/;394}395396$ENV{CLASSPATH} = munge $ENV{CLASSPATH} if exists $ENV{CLASSPATH};397@ARGV = ("java", @ARGV);398print "@ARGV\n";399exec @ARGV;400401*/402403404