src/share/tools/launcher/wildcard.c

Fri, 29 Mar 2013 14:18:40 -0700

author
ccheung
date
Fri, 29 Mar 2013 14:18:40 -0700
changeset 4887
bad3bed4b323
parent 2327
cb2d0a362639
permissions
-rw-r--r--

8006006: [parfait] Memory leak at hotspot/src/share/tools/launcher/wildcard.c
Summary: a simple fix to add FileList_free(fl) before returning NULL.
Reviewed-by: zgu, coleenp, minqi

     1 /*
     2  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 /*
    26  * Class-Path Wildcards
    27  *
    28  * The syntax for wildcards is a single asterisk. The class path
    29  * 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 particular
    34  * magic number, regardless of filename extension, are not
    35  * matched.
    36  *
    37  * Files are considered regardless of whether or not they are
    38  * "hidden" in the UNIX sense, i.e., have names beginning with '.'.
    39  *
    40  * A wildcard only matches jar files, not class files in the same
    41  * directory.  If you want to load both class files and jar files from
    42  * a single directory foo then you can say foo:foo/"*", or foo/"*":foo
    43  * if you want the jar files to take precedence.
    44  *
    45  * Subdirectories are not searched recursively, i.e., foo/"*" only
    46  * 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 a
    49  * program's main method, rather than late, during the class-loading
    50  * process itself.  Each element of the input class path containing a
    51  * wildcard is replaced by the (possibly empty) sequence of elements
    52  * generated by enumerating the jar files in the named directory.  If
    53  * the directory foo contains a.jar, b.jar, and c.jar,
    54  * e.g., then the class path foo/"*" is expanded into
    55  * foo/a.jar:foo/b.jar:foo/c.jar, and that string would be the value
    56  * of the system property java.class.path.
    57  *
    58  * The order in which the jar files in a directory are enumerated in
    59  * the expanded class path is not specified and may vary from platform
    60  * to platform and even from moment to moment on the same machine.  A
    61  * well-constructed application should not depend upon any particular
    62  * order.  If a specific order is required then the jar files can be
    63  * enumerated explicitly in the class path.
    64  *
    65  * The CLASSPATH environment variable is not treated any differently
    66  * 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-manifest
    70  * header.
    71  *
    72  * Class-path wildcards are honored not only by the Java launcher but
    73  * also by most other command-line tools that accept class paths, and
    74  * in particular by javac and javadoc.
    75  *
    76  * Class-path wildcards are not honored in any other kind of path, and
    77  * especially not in the bootstrap class path, which is a mere
    78  * artifact of our implementation and not something that developers
    79  * 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 the
    83  * CLASSPATH environment variable.  We do not support the use of
    84  * wildcards by applications that embed the JVM.
    85  */
    87 #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"
    95 #ifdef _WIN32
    96 #include <windows.h>
    97 #else /* Unix */
    98 #include <unistd.h>
    99 #include <dirent.h>
   100 #endif /* Unix */
   102 static int
   103 exists(const char* filename)
   104 {
   105 #ifdef _WIN32
   106     return _access(filename, 0) == 0;
   107 #else
   108     return access(filename, F_OK) == 0;
   109 #endif
   110 }
   112 #define NEW_(TYPE) ((TYPE) JLI_MemAlloc(sizeof(struct TYPE##_)))
   114 /*
   115  * Wildcard directory iteration.
   116  * WildcardIterator_for(wildcard) returns an iterator.
   117  * Each call to that iterator's next() method returns the basename
   118  * of an entry in the wildcard's directory.  The basename's memory
   119  * belongs to the iterator.  The caller is responsible for prepending
   120  * the directory name and file separator, if necessary.
   121  * When done with the iterator, call the close method to clean up.
   122  */
   123 typedef struct WildcardIterator_* WildcardIterator;
   125 #ifdef _WIN32
   126 struct WildcardIterator_
   127 {
   128     HANDLE handle;
   129     char *firstFile; /* Stupid FindFirstFile...FindNextFile */
   130 };
   132 static WildcardIterator
   133 WildcardIterator_for(const char *wildcard)
   134 {
   135     WIN32_FIND_DATA find_data;
   136     WildcardIterator it = NEW_(WildcardIterator);
   137     HANDLE handle = FindFirstFile(wildcard, &find_data);
   138     if (handle == INVALID_HANDLE_VALUE)
   139         return NULL;
   140     it->handle = handle;
   141     it->firstFile = find_data.cFileName;
   142     return it;
   143 }
   145 static char *
   146 WildcardIterator_next(WildcardIterator it)
   147 {
   148     WIN32_FIND_DATA find_data;
   149     if (it->firstFile != NULL) {
   150         char *firstFile = it->firstFile;
   151         it->firstFile = NULL;
   152         return firstFile;
   153     }
   154     return FindNextFile(it->handle, &find_data)
   155         ? find_data.cFileName : NULL;
   156 }
   158 static void
   159 WildcardIterator_close(WildcardIterator it)
   160 {
   161     if (it) {
   162         FindClose(it->handle);
   163         JLI_MemFree(it->firstFile);
   164         JLI_MemFree(it);
   165     }
   166 }
   168 #else /* Unix */
   169 struct WildcardIterator_
   170 {
   171     DIR *dir;
   172 };
   174 static WildcardIterator
   175 WildcardIterator_for(const char *wildcard)
   176 {
   177     DIR *dir;
   178     int wildlen = strlen(wildcard);
   179     if (wildlen < 2) {
   180         dir = opendir(".");
   181     } else {
   182         char *dirname = JLI_StringDup(wildcard);
   183         dirname[wildlen - 1] = '\0';
   184         dir = opendir(dirname);
   185         JLI_MemFree(dirname);
   186     }
   187     if (dir == NULL)
   188         return NULL;
   189     else {
   190         WildcardIterator it = NEW_(WildcardIterator);
   191         it->dir = dir;
   192         return it;
   193     }
   194 }
   196 static char *
   197 WildcardIterator_next(WildcardIterator it)
   198 {
   199     struct dirent* dirp = readdir(it->dir);
   200     return dirp ? dirp->d_name : NULL;
   201 }
   203 static void
   204 WildcardIterator_close(WildcardIterator it)
   205 {
   206     if (it) {
   207         closedir(it->dir);
   208         JLI_MemFree(it);
   209     }
   210 }
   211 #endif /* Unix */
   213 static int
   214 equal(const char *s1, const char *s2)
   215 {
   216     return strcmp(s1, s2) == 0;
   217 }
   219 /*
   220  * FileList ADT - a dynamic list of C filenames
   221  */
   222 struct FileList_
   223 {
   224     char **files;
   225     int size;
   226     int capacity;
   227 };
   228 typedef struct FileList_ *FileList;
   230 static FileList
   231 FileList_new(int capacity)
   232 {
   233     FileList fl = NEW_(FileList);
   234     fl->capacity = capacity;
   235     fl->files = (char **) JLI_MemAlloc(capacity * sizeof(fl->files[0]));
   236     fl->size = 0;
   237     return fl;
   238 }
   240 #ifdef DEBUG_WILDCARD
   241 static void
   242 FileList_print(FileList fl)
   243 {
   244     int i;
   245     putchar('[');
   246     for (i = 0; i < fl->size; i++) {
   247         if (i > 0) printf(", ");
   248         printf("\"%s\"",fl->files[i]);
   249     }
   250     putchar(']');
   251 }
   252 #endif
   254 static void
   255 FileList_free(FileList fl)
   256 {
   257     if (fl) {
   258         if (fl->files) {
   259             int i;
   260             for (i = 0; i < fl->size; i++)
   261                 JLI_MemFree(fl->files[i]);
   262             JLI_MemFree(fl->files);
   263         }
   264         JLI_MemFree(fl);
   265     }
   266 }
   268 static void
   269 FileList_ensureCapacity(FileList fl, int capacity)
   270 {
   271     if (fl->capacity < capacity) {
   272         while (fl->capacity < capacity)
   273             fl->capacity *= 2;
   274         fl->files = JLI_MemRealloc(fl->files,
   275                                fl->capacity * sizeof(fl->files[0]));
   276     }
   277 }
   279 static void
   280 FileList_add(FileList fl, char *file)
   281 {
   282     FileList_ensureCapacity(fl, fl->size+1);
   283     fl->files[fl->size++] = file;
   284 }
   286 static void
   287 FileList_addSubstring(FileList fl, const char *beg, int len)
   288 {
   289     char *filename = (char *) JLI_MemAlloc(len+1);
   290     memcpy(filename, beg, len);
   291     filename[len] = '\0';
   292     FileList_ensureCapacity(fl, fl->size+1);
   293     fl->files[fl->size++] = filename;
   294 }
   296 static char *
   297 FileList_join(FileList fl, char sep)
   298 {
   299     int i;
   300     int size;
   301     char *path;
   302     char *p;
   303     for (i = 0, size = 1; i < fl->size; i++)
   304         size += strlen(fl->files[i]) + 1;
   306     path = JLI_MemAlloc(size);
   308     for (i = 0, p = path; i < fl->size; i++) {
   309         int len = strlen(fl->files[i]);
   310         if (i > 0) *p++ = sep;
   311         memcpy(p, fl->files[i], len);
   312         p += len;
   313     }
   314     *p = '\0';
   316     return path;
   317 }
   319 static FileList
   320 FileList_split(const char *path, char sep)
   321 {
   322     const char *p, *q;
   323     int len = strlen(path);
   324     int count;
   325     FileList fl;
   326     for (count = 1, p = path; p < path + len; p++)
   327         count += (*p == sep);
   328     fl = FileList_new(count);
   329     for (p = path;;) {
   330         for (q = p; q <= path + len; q++) {
   331             if (*q == sep || *q == '\0') {
   332                 FileList_addSubstring(fl, p, q - p);
   333                 if (*q == '\0')
   334                     return fl;
   335                 p = q + 1;
   336             }
   337         }
   338     }
   339 }
   341 static int
   342 isJarFileName(const char *filename)
   343 {
   344     int len = strlen(filename);
   345     return (len >= 4) &&
   346         (filename[len - 4] == '.') &&
   347         (equal(filename + len - 3, "jar") ||
   348          equal(filename + len - 3, "JAR")) &&
   349         /* Paranoia: Maybe filename is "DIR:foo.jar" */
   350         (strchr(filename, PATH_SEPARATOR) == NULL);
   351 }
   353 static char *
   354 wildcardConcat(const char *wildcard, const char *basename)
   355 {
   356     int wildlen = strlen(wildcard);
   357     int baselen = strlen(basename);
   358     char *filename = (char *) JLI_MemAlloc(wildlen + baselen);
   359     /* Replace the trailing '*' with basename */
   360     memcpy(filename, wildcard, wildlen-1);
   361     memcpy(filename+wildlen-1, basename, baselen+1);
   362     return filename;
   363 }
   365 static FileList
   366 wildcardFileList(const char *wildcard)
   367 {
   368     const char *basename;
   369     FileList fl = FileList_new(16);
   370     WildcardIterator it = WildcardIterator_for(wildcard);
   371     if (it == NULL) {
   372         FileList_free(fl);
   373         return NULL;
   374     }
   375     while ((basename = WildcardIterator_next(it)) != NULL)
   376         if (isJarFileName(basename))
   377             FileList_add(fl, wildcardConcat(wildcard, basename));
   378     WildcardIterator_close(it);
   379     return fl;
   380 }
   382 static int
   383 isWildcard(const char *filename)
   384 {
   385     int len = strlen(filename);
   386     return (len > 0) &&
   387         (filename[len - 1] == '*') &&
   388         (len == 1 || IS_FILE_SEPARATOR(filename[len - 2])) &&
   389         (! exists(filename));
   390 }
   392 static void
   393 FileList_expandWildcards(FileList fl)
   394 {
   395     int i, j;
   396     for (i = 0; i < fl->size; i++) {
   397         if (isWildcard(fl->files[i])) {
   398             FileList expanded = wildcardFileList(fl->files[i]);
   399             if (expanded != NULL && expanded->size > 0) {
   400                 JLI_MemFree(fl->files[i]);
   401                 FileList_ensureCapacity(fl, fl->size + expanded->size);
   402                 for (j = fl->size - 1; j >= i+1; j--)
   403                     fl->files[j+expanded->size-1] = fl->files[j];
   404                 for (j = 0; j < expanded->size; j++)
   405                     fl->files[i+j] = expanded->files[j];
   406                 i += expanded->size - 1;
   407                 fl->size += expanded->size - 1;
   408                 /* fl expropriates expanded's elements. */
   409                 expanded->size = 0;
   410             }
   411             FileList_free(expanded);
   412         }
   413     }
   414 }
   416 const char *
   417 JLI_WildcardExpandClasspath(const char *classpath)
   418 {
   419     char *expanded;
   420     FileList fl;
   422     if (strchr(classpath, '*') == NULL)
   423         return classpath;
   424     fl = FileList_split(classpath, PATH_SEPARATOR);
   425     FileList_expandWildcards(fl);
   426     expanded = FileList_join(fl, PATH_SEPARATOR);
   427     FileList_free(fl);
   428     if (getenv("_JAVA_LAUNCHER_DEBUG") != 0)
   429         printf("Expanded wildcards:\n"
   430                "    before: \"%s\"\n"
   431                "    after : \"%s\"\n",
   432                classpath, expanded);
   433     return expanded;
   434 }
   436 #ifdef DEBUG_WILDCARD
   437 static void
   438 wildcardExpandArgv(const char ***argv)
   439 {
   440     int i;
   441     for (i = 0; (*argv)[i]; i++) {
   442         if (equal((*argv)[i], "-cp") ||
   443             equal((*argv)[i], "-classpath")) {
   444             i++;
   445             (*argv)[i] = wildcardExpandClasspath((*argv)[i]);
   446         }
   447     }
   448 }
   450 static void
   451 debugPrintArgv(char *argv[])
   452 {
   453     int i;
   454     putchar('[');
   455     for (i = 0; argv[i]; i++) {
   456         if (i > 0) printf(", ");
   457         printf("\"%s\"", argv[i]);
   458     }
   459     printf("]\n");
   460 }
   462 int
   463 main(int argc, char *argv[])
   464 {
   465     argv[0] = "java";
   466     wildcardExpandArgv((const char***)&argv);
   467     debugPrintArgv(argv);
   468     /* execvp("java", argv); */
   469     return 0;
   470 }
   471 #endif /* DEBUG_WILDCARD */
   473 /* Cute little perl prototype implementation....
   475 my $sep = ($^O =~ /^(Windows|cygwin)/) ? ";" : ":";
   477 sub expand($) {
   478   opendir DIR, $_[0] or return $_[0];
   479   join $sep, map {"$_[0]/$_"} grep {/\.(jar|JAR)$/} readdir DIR;
   480 }
   482 sub munge($) {
   483   join $sep,
   484     map {(! -r $_ and s/[\/\\]+\*$//) ? expand $_ : $_} split $sep, $_[0];
   485 }
   487 for (my $i = 0; $i < @ARGV - 1; $i++) {
   488   $ARGV[$i+1] = munge $ARGV[$i+1] if $ARGV[$i] =~ /^-c(p|lasspath)$/;
   489 }
   491 $ENV{CLASSPATH} = munge $ENV{CLASSPATH} if exists $ENV{CLASSPATH};
   492 @ARGV = ("java", @ARGV);
   493 print "@ARGV\n";
   494 exec @ARGV;
   496 */

mercurial