summaryrefslogtreecommitdiff
path: root/usr/src/make_src/Make/bin/make/common/files.cc
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/make_src/Make/bin/make/common/files.cc')
-rw-r--r--usr/src/make_src/Make/bin/make/common/files.cc733
1 files changed, 733 insertions, 0 deletions
diff --git a/usr/src/make_src/Make/bin/make/common/files.cc b/usr/src/make_src/Make/bin/make/common/files.cc
new file mode 100644
index 0000000..6ca6919
--- /dev/null
+++ b/usr/src/make_src/Make/bin/make/common/files.cc
@@ -0,0 +1,733 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * @(#)files.cc 1.37 06/12/12
+ */
+
+#pragma ident "@(#)files.cc 1.37 06/12/12"
+
+/*
+ * files.c
+ *
+ * Various file related routines:
+ * Figure out if file exists
+ * Wildcard resolution for directory reader
+ * Directory reader
+ */
+
+
+/*
+ * Included files
+ */
+#if defined(SUN5_0) || defined(HP_UX)
+#include <dirent.h> /* opendir() */
+#else
+#include <sys/dir.h> /* opendir() */
+#endif
+#include <errno.h> /* errno */
+#include <mk/defs.h>
+#include <mksh/macro.h> /* getvar() */
+#include <mksh/misc.h> /* get_prop(), append_prop() */
+#include <sys/stat.h> /* lstat() */
+
+/*
+ * Defined macros
+ */
+
+/*
+ * typedefs & structs
+ */
+
+/*
+ * Static variables
+ */
+
+/*
+ * File table of contents
+ */
+extern timestruc_t& exists(register Name target);
+extern void set_target_stat(register Name target, struct stat buf);
+static timestruc_t& vpath_exists(register Name target);
+static Name enter_file_name(wchar_t *name_string, wchar_t *library);
+static Boolean star_match(register char *string, register char *pattern);
+static Boolean amatch(register wchar_t *string, register wchar_t *pattern);
+
+/*
+ * exists(target)
+ *
+ * Figure out the timestamp for one target.
+ *
+ * Return value:
+ * The time the target was created
+ *
+ * Parameters:
+ * target The target to check
+ *
+ * Global variables used:
+ * debug_level Should we trace the stat call?
+ * recursion_level Used for tracing
+ * vpath_defined Was the variable VPATH defined in environment?
+ */
+timestruc_t&
+exists(register Name target)
+{
+ struct stat buf;
+ register int result;
+
+ /* We cache stat information. */
+ if (target->stat.time != file_no_time) {
+ return target->stat.time;
+ }
+
+ /*
+ * If the target is a member, we have to extract the time
+ * from the archive.
+ */
+ if (target->is_member &&
+ (get_prop(target->prop, member_prop) != NULL)) {
+ return read_archive(target);
+ }
+
+ if (debug_level > 1) {
+ (void) printf(NOCATGETS("%*sstat(%s)\n"),
+ recursion_level,
+ "",
+ target->string_mb);
+ }
+
+ result = lstat_vroot(target->string_mb, &buf, NULL, VROOT_DEFAULT);
+ if ((result != -1) && ((buf.st_mode & S_IFMT) == S_IFLNK)) {
+ /*
+ * If the file is a symbolic link, we remember that
+ * and then we get the status for the refd file.
+ */
+ target->stat.is_sym_link = true;
+ result = stat_vroot(target->string_mb, &buf, NULL, VROOT_DEFAULT);
+ } else {
+ target->stat.is_sym_link = false;
+ }
+
+ if (result < 0) {
+ target->stat.time = file_doesnt_exist;
+ target->stat.stat_errno = errno;
+ if ((errno == ENOENT) &&
+ vpath_defined &&
+/* azv, fixing bug 1262942, VPATH works with a leaf name
+ * but not a directory name.
+ */
+ (target->string_mb[0] != (int) slash_char) ) {
+/* BID_1214655 */
+/* azv */
+ vpath_exists(target);
+ // return vpath_exists(target);
+ }
+ } else {
+ /* Save all the information we need about the file */
+ target->stat.stat_errno = 0;
+ target->stat.is_file = true;
+ target->stat.mode = buf.st_mode & 0777;
+ target->stat.size = buf.st_size;
+ target->stat.is_dir =
+ BOOLEAN((buf.st_mode & S_IFMT) == S_IFDIR);
+ if (target->stat.is_dir) {
+ target->stat.time = file_is_dir;
+ } else {
+ /* target->stat.time = buf.st_mtime; */
+/* BID_1129806 */
+/* vis@nbsp.nsk.su */
+#if defined(linux)
+ timestruc_t ttime = { buf.st_mtime, 0 };
+ target->stat.time = MAX(ttime, file_min_time);
+#else
+ target->stat.time = MAX(buf.st_mtim, file_min_time);
+#endif
+ }
+ }
+ if ((target->colon_splits > 0) &&
+ (get_prop(target->prop, time_prop) == NULL)) {
+ append_prop(target, time_prop)->body.time.time =
+ target->stat.time;
+ }
+ return target->stat.time;
+}
+
+/*
+ * set_target_stat( target, buf)
+ *
+ * Called by exists() to set some stat fields in the Name structure
+ * to those read by the stat_vroot() call (from disk).
+ *
+ * Parameters:
+ * target The target whose stat field is set
+ * buf stat values (on disk) of the file
+ * represented by target.
+ */
+void
+set_target_stat(register Name target, struct stat buf)
+{
+ target->stat.stat_errno = 0;
+ target->stat.is_file = true;
+ target->stat.mode = buf.st_mode & 0777;
+ target->stat.size = buf.st_size;
+ target->stat.is_dir =
+ BOOLEAN((buf.st_mode & S_IFMT) == S_IFDIR);
+ if (target->stat.is_dir) {
+ target->stat.time = file_is_dir;
+ } else {
+ /* target->stat.time = buf.st_mtime; */
+/* BID_1129806 */
+/* vis@nbsp.nsk.su */
+#if defined(linux)
+ timestruc_t ttime = { buf.st_mtime, 0 };
+ target->stat.time = ttime;
+#else
+ target->stat.time = MAX(buf.st_mtim, file_min_time);
+#endif
+ }
+}
+
+
+/*
+ * vpath_exists(target)
+ *
+ * Called if exists() discovers that there is a VPATH defined.
+ * This function stats the VPATH translation of the target.
+ *
+ * Return value:
+ * The time the target was created
+ *
+ * Parameters:
+ * target The target to check
+ *
+ * Global variables used:
+ * vpath_name The Name "VPATH", used to get macro value
+ */
+static timestruc_t&
+vpath_exists(register Name target)
+{
+ wchar_t *vpath;
+ wchar_t file_name[MAXPATHLEN];
+ wchar_t *name_p;
+ Name alias;
+
+ /*
+ * To avoid recursive search through VPATH when exists(alias) is called
+ */
+ vpath_defined = false;
+
+ Wstring wcb(getvar(vpath_name));
+ Wstring wcb1(target);
+
+ vpath = wcb.get_string();
+
+ while (*vpath != (int) nul_char) {
+ name_p = file_name;
+ while ((*vpath != (int) colon_char) &&
+ (*vpath != (int) nul_char)) {
+ *name_p++ = *vpath++;
+ }
+ *name_p++ = (int) slash_char;
+ (void) wscpy(name_p, wcb1.get_string());
+ alias = GETNAME(file_name, FIND_LENGTH);
+ if (exists(alias) != file_doesnt_exist) {
+ target->stat.is_file = true;
+ target->stat.mode = alias->stat.mode;
+ target->stat.size = alias->stat.size;
+ target->stat.is_dir = alias->stat.is_dir;
+ target->stat.time = alias->stat.time;
+ maybe_append_prop(target, vpath_alias_prop)->
+ body.vpath_alias.alias = alias;
+ target->has_vpath_alias_prop = true;
+ vpath_defined = true;
+ return alias->stat.time;
+ }
+ while ((*vpath != (int) nul_char) &&
+ ((*vpath == (int) colon_char) || iswspace(*vpath))) {
+ vpath++;
+ }
+ }
+ /*
+ * Restore vpath_defined
+ */
+ vpath_defined = true;
+ return target->stat.time;
+}
+
+/*
+ * read_dir(dir, pattern, line, library)
+ *
+ * Used to enter the contents of directories into makes namespace.
+ * Presence of a file is important when scanning for implicit rules.
+ * read_dir() is also used to expand wildcards in dependency lists.
+ *
+ * Return value:
+ * Non-0 if we found files to match the pattern
+ *
+ * Parameters:
+ * dir Path to the directory to read
+ * pattern Pattern for that files should match or NULL
+ * line When we scan using a pattern we enter files
+ * we find as dependencies for this line
+ * library If we scan for "lib.a(<wildcard-member>)"
+ *
+ * Global variables used:
+ * debug_level Should we trace the dir reading?
+ * dot The Name ".", compared against
+ * sccs_dir_path The path to the SCCS dir (from PROJECTDIR)
+ * vpath_defined Was the variable VPATH defined in environment?
+ * vpath_name The Name "VPATH", use to get macro value
+ */
+int
+read_dir(Name dir, wchar_t *pattern, Property line, wchar_t *library)
+{
+ wchar_t file_name[MAXPATHLEN];
+ wchar_t *file_name_p = file_name;
+ Name file;
+ wchar_t plain_file_name[MAXPATHLEN];
+ wchar_t *plain_file_name_p;
+ Name plain_file;
+ wchar_t tmp_wcs_buffer[MAXPATHLEN];
+ DIR *dir_fd;
+ int m_local_dependency=0;
+#if defined(SUN5_0) || defined(HP_UX)
+#define d_fileno d_ino
+ register struct dirent *dp;
+#else
+ register struct direct *dp;
+#endif
+ wchar_t *vpath = NULL;
+ wchar_t *p;
+ int result = 0;
+
+ if(dir->hash.length >= MAXPATHLEN) {
+ return 0;
+ }
+
+ Wstring wcb(dir);
+ Wstring vps;
+
+ /* A directory is only read once unless we need to expand wildcards. */
+ if (pattern == NULL) {
+ if (dir->has_read_dir) {
+ return 0;
+ }
+ dir->has_read_dir = true;
+ }
+ /* Check if VPATH is active and setup list if it is. */
+ if (vpath_defined && (dir == dot)) {
+ vps.init(getvar(vpath_name));
+ vpath = vps.get_string();
+ }
+
+ /*
+ * Prepare the string where we build the full name of the
+ * files in the directory.
+ */
+ if ((dir->hash.length > 1) || (wcb.get_string()[0] != (int) period_char)) {
+ (void) wscpy(file_name, wcb.get_string());
+ MBSTOWCS(wcs_buffer, "/");
+ (void) wscat(file_name, wcs_buffer);
+ file_name_p = file_name + wslen(file_name);
+ }
+
+ /* Open the directory. */
+vpath_loop:
+ dir_fd = opendir(dir->string_mb);
+ if (dir_fd == NULL) {
+ return 0;
+ }
+
+ /* Read all the directory entries. */
+ while ((dp = readdir(dir_fd)) != NULL) {
+ /* We ignore "." and ".." */
+ if ((dp->d_fileno == 0) ||
+ ((dp->d_name[0] == (int) period_char) &&
+ ((dp->d_name[1] == 0) ||
+ ((dp->d_name[1] == (int) period_char) &&
+ (dp->d_name[2] == 0))))) {
+ continue;
+ }
+ /*
+ * Build the full name of the file using whatever
+ * path supplied to the function.
+ */
+ MBSTOWCS(tmp_wcs_buffer, dp->d_name);
+ (void) wscpy(file_name_p, tmp_wcs_buffer);
+ file = enter_file_name(file_name, library);
+ if ((pattern != NULL) && amatch(tmp_wcs_buffer, pattern)) {
+ /*
+ * If we are expanding a wildcard pattern, we
+ * enter the file as a dependency for the target.
+ */
+ if (debug_level > 0){
+ WCSTOMBS(mbs_buffer, pattern);
+ (void) printf(catgets(catd, 1, 231, "'%s: %s' due to %s expansion\n"),
+ line->body.line.target->string_mb,
+ file->string_mb,
+ mbs_buffer);
+ }
+ enter_dependency(line, file, false);
+ result++;
+ } else {
+ /*
+ * If the file has an SCCS/s. file,
+ * we will detect that later on.
+ */
+ file->stat.has_sccs = NO_SCCS;
+ /*
+ * If this is an s. file, we also enter it as if it
+ * existed in the plain directory.
+ */
+ if ((dp->d_name[0] == 's') &&
+ (dp->d_name[1] == (int) period_char)) {
+
+ MBSTOWCS(tmp_wcs_buffer, dp->d_name + 2);
+ plain_file_name_p = plain_file_name;
+ (void) wscpy(plain_file_name_p, tmp_wcs_buffer);
+ plain_file = GETNAME(plain_file_name, FIND_LENGTH);
+ plain_file->stat.is_file = true;
+ plain_file->stat.has_sccs = HAS_SCCS;
+ /*
+ * Enter the s. file as a dependency for the
+ * plain file.
+ */
+ maybe_append_prop(plain_file, sccs_prop)->
+ body.sccs.file = file;
+ MBSTOWCS(tmp_wcs_buffer, dp->d_name + 2);
+ if ((pattern != NULL) &&
+ amatch(tmp_wcs_buffer, pattern)) {
+ if (debug_level > 0) {
+ WCSTOMBS(mbs_buffer, pattern);
+ (void) printf(catgets(catd, 1, 232, "'%s: %s' due to %s expansion\n"),
+ line->body.line.target->
+ string_mb,
+ plain_file->string_mb,
+ mbs_buffer);
+ }
+ enter_dependency(line, plain_file, false);
+ result++;
+ }
+ }
+ }
+ }
+ (void) closedir(dir_fd);
+ if ((vpath != NULL) && (*vpath != (int) nul_char)) {
+ while ((*vpath != (int) nul_char) &&
+ (iswspace(*vpath) || (*vpath == (int) colon_char))) {
+ vpath++;
+ }
+ p = vpath;
+ while ((*vpath != (int) colon_char) &&
+ (*vpath != (int) nul_char)) {
+ vpath++;
+ }
+ if (vpath > p) {
+ dir = GETNAME(p, vpath - p);
+ goto vpath_loop;
+ }
+ }
+/*
+ * look into SCCS directory only if it's not svr4. For svr4 dont do that.
+ */
+
+/*
+ * Now read the SCCS directory.
+ * Files in the SCSC directory are considered to be part of the set of
+ * files in the plain directory. They are also entered in their own right.
+ * Prepare the string where we build the true name of the SCCS files.
+ */
+ (void) wsncpy(plain_file_name,
+ file_name,
+ file_name_p - file_name);
+ plain_file_name[file_name_p - file_name] = 0;
+ plain_file_name_p = plain_file_name + wslen(plain_file_name);
+
+ if(!svr4) {
+
+ if (sccs_dir_path != NULL) {
+ wchar_t tmp_wchar;
+ wchar_t path[MAXPATHLEN];
+ char mb_path[MAXPATHLEN];
+
+ if (file_name_p - file_name > 0) {
+ tmp_wchar = *file_name_p;
+ *file_name_p = 0;
+ WCSTOMBS(mbs_buffer, file_name);
+ (void) sprintf(mb_path, NOCATGETS("%s/%s/SCCS"),
+ sccs_dir_path,
+ mbs_buffer);
+ *file_name_p = tmp_wchar;
+ } else {
+ (void) sprintf(mb_path, NOCATGETS("%s/SCCS"), sccs_dir_path);
+ }
+ MBSTOWCS(path, mb_path);
+ (void) wscpy(file_name, path);
+ } else {
+ MBSTOWCS(wcs_buffer, NOCATGETS("SCCS"));
+ (void) wscpy(file_name_p, wcs_buffer);
+ }
+ } else {
+ MBSTOWCS(wcs_buffer, NOCATGETS("."));
+ (void) wscpy(file_name_p, wcs_buffer);
+ }
+ /* Internalize the constructed SCCS dir name. */
+ (void) exists(dir = GETNAME(file_name, FIND_LENGTH));
+ /* Just give up if the directory file doesnt exist. */
+ if (!dir->stat.is_file) {
+ return result;
+ }
+ /* Open the directory. */
+ dir_fd = opendir(dir->string_mb);
+ if (dir_fd == NULL) {
+ return result;
+ }
+ MBSTOWCS(wcs_buffer, "/");
+ (void) wscat(file_name, wcs_buffer);
+ file_name_p = file_name + wslen(file_name);
+
+ while ((dp = readdir(dir_fd)) != NULL) {
+ if ((dp->d_fileno == 0) ||
+ ((dp->d_name[0] == (int) period_char) &&
+ ((dp->d_name[1] == 0) ||
+ ((dp->d_name[1] == (int) period_char) &&
+ (dp->d_name[2] == 0))))) {
+ continue;
+ }
+ /* Construct and internalize the true name of the SCCS file. */
+ MBSTOWCS(wcs_buffer, dp->d_name);
+ (void) wscpy(file_name_p, wcs_buffer);
+ file = GETNAME(file_name, FIND_LENGTH);
+ file->stat.is_file = true;
+ file->stat.has_sccs = NO_SCCS;
+ /*
+ * If this is an s. file, we also enter it as if it
+ * existed in the plain directory.
+ */
+ if ((dp->d_name[0] == 's') &&
+ (dp->d_name[1] == (int) period_char)) {
+
+ MBSTOWCS(wcs_buffer, dp->d_name + 2);
+ (void) wscpy(plain_file_name_p, wcs_buffer);
+ plain_file = GETNAME(plain_file_name, FIND_LENGTH);
+ plain_file->stat.is_file = true;
+ plain_file->stat.has_sccs = HAS_SCCS;
+ /* if sccs dependency is already set,skip */
+ if(plain_file->prop) {
+ Property sprop = get_prop(plain_file->prop,sccs_prop);
+ if(sprop != NULL) {
+ if (sprop->body.sccs.file) {
+ goto try_pattern;
+ }
+ }
+ }
+
+ /*
+ * Enter the s. file as a dependency for the
+ * plain file.
+ */
+ maybe_append_prop(plain_file, sccs_prop)->
+ body.sccs.file = file;
+try_pattern:
+ MBSTOWCS(tmp_wcs_buffer, dp->d_name + 2);
+ if ((pattern != NULL) &&
+ amatch(tmp_wcs_buffer, pattern)) {
+ if (debug_level > 0) {
+ WCSTOMBS(mbs_buffer, pattern);
+ (void) printf(catgets(catd, 1, 233, "'%s: %s' due to %s expansion\n"),
+ line->body.line.target->
+ string_mb,
+ plain_file->string_mb,
+ mbs_buffer);
+ }
+ enter_dependency(line, plain_file, false);
+ result++;
+ }
+ }
+ }
+ (void) closedir(dir_fd);
+
+ return result;
+}
+
+/*
+ * enter_file_name(name_string, library)
+ *
+ * Helper function for read_dir().
+ *
+ * Return value:
+ * The Name that was entered
+ *
+ * Parameters:
+ * name_string Name of the file we want to enter
+ * library The library it is a member of, if any
+ *
+ * Global variables used:
+ */
+static Name
+enter_file_name(wchar_t *name_string, wchar_t *library)
+{
+ wchar_t buffer[STRING_BUFFER_LENGTH];
+ String_rec lib_name;
+ Name name;
+ Property prop;
+
+ if (library == NULL) {
+ name = GETNAME(name_string, FIND_LENGTH);
+ name->stat.is_file = true;
+ return name;
+ }
+
+ INIT_STRING_FROM_STACK(lib_name, buffer);
+ append_string(library, &lib_name, FIND_LENGTH);
+ append_char((int) parenleft_char, &lib_name);
+ append_string(name_string, &lib_name, FIND_LENGTH);
+ append_char((int) parenright_char, &lib_name);
+
+ name = GETNAME(lib_name.buffer.start, FIND_LENGTH);
+ name->stat.is_file = true;
+ name->is_member = true;
+ prop = maybe_append_prop(name, member_prop);
+ prop->body.member.library = GETNAME(library, FIND_LENGTH);
+ prop->body.member.library->stat.is_file = true;
+ prop->body.member.entry = NULL;
+ prop->body.member.member = GETNAME(name_string, FIND_LENGTH);
+ prop->body.member.member->stat.is_file = true;
+ return name;
+}
+
+/*
+ * star_match(string, pattern)
+ *
+ * This is a regular shell type wildcard pattern matcher
+ * It is used when xpanding wildcards in dependency lists
+ *
+ * Return value:
+ * Indication if the string matched the pattern
+ *
+ * Parameters:
+ * string String to match
+ * pattern Pattern to match it against
+ *
+ * Global variables used:
+ */
+static Boolean
+star_match(register wchar_t *string, register wchar_t *pattern)
+{
+ register int pattern_ch;
+
+ switch (*pattern) {
+ case 0:
+ return succeeded;
+ case bracketleft_char:
+ case question_char:
+ case asterisk_char:
+ while (*string) {
+ if (amatch(string++, pattern)) {
+ return succeeded;
+ }
+ }
+ break;
+ default:
+ pattern_ch = (int) *pattern++;
+ while (*string) {
+ if ((*string++ == pattern_ch) &&
+ amatch(string, pattern)) {
+ return succeeded;
+ }
+ }
+ break;
+ }
+ return failed;
+}
+
+/*
+ * amatch(string, pattern)
+ *
+ * Helper function for shell pattern matching
+ *
+ * Return value:
+ * Indication if the string matched the pattern
+ *
+ * Parameters:
+ * string String to match
+ * pattern Pattern to match it against
+ *
+ * Global variables used:
+ */
+static Boolean
+amatch(register wchar_t *string, register wchar_t *pattern)
+{
+ register long lower_bound;
+ register long string_ch;
+ register long pattern_ch;
+ register int k;
+
+top:
+ for (; 1; pattern++, string++) {
+ lower_bound = 017777777777;
+ string_ch = *string;
+ switch (pattern_ch = *pattern) {
+ case bracketleft_char:
+ k = 0;
+ while ((pattern_ch = *++pattern) != 0) {
+ switch (pattern_ch) {
+ case bracketright_char:
+ if (!k) {
+ return failed;
+ }
+ string++;
+ pattern++;
+ goto top;
+ case hyphen_char:
+ k |= (lower_bound <= string_ch) &&
+ (string_ch <=
+ (pattern_ch = pattern[1]));
+ default:
+ if (string_ch ==
+ (lower_bound = pattern_ch)) {
+ k++;
+ }
+ }
+ }
+ return failed;
+ case asterisk_char:
+ return star_match(string, ++pattern);
+ case 0:
+ return BOOLEAN(!string_ch);
+ case question_char:
+ if (string_ch == 0) {
+ return failed;
+ }
+ break;
+ default:
+ if (pattern_ch != string_ch) {
+ return failed;
+ }
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
+