diff options
author | Igor Pashev <igor.pashev@nexenta.com> | 2012-06-29 14:36:07 +0400 |
---|---|---|
committer | Igor Pashev <igor.pashev@nexenta.com> | 2012-06-29 14:36:07 +0400 |
commit | e0463df9c3d2ee6155221cc443c571d5da47098a (patch) | |
tree | 5c6b99e64c1b65d986e2722728c74f202a578be6 /usr/src/make_src/Make/bin/make/common/files.cc | |
download | sunmake-e0463df9c3d2ee6155221cc443c571d5da47098a.tar.gz |
Initial import of DevPro make sourcesorig
Downloaded from http://dlc.sun.com/osol/devpro/downloads/current/
Licensed under CDDL http://www.opensource.org/licenses/CDDL-1.0
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.cc | 733 |
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 */ +} + |