// // aegis - project change supervisor // Copyright (C) 2002-2006, 2008, 2011, 2012, 2014 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or (at // your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // #include #include #include #include #include #include #include #include #include #include string_ty * dir_stack_find(string_list_ty *stack, size_t start_pos, string_ty *path, struct stat *st, int *depth_p, int ignore_symlinks) { size_t j; string_ty *dir; string_ty *resolved_path; struct stat bogus; string_ty *maybe_pathname = 0; int maybe_depth = 0; struct stat maybe_statbuf; trace(("dir_stack_find(path = \"%s\")\n{\n", path->str_text)); if (!st) st = &bogus; for (j = start_pos; j < stack->size(); ++j) { dir = (*stack)[j]; resolved_path = os_path_cat(dir, path); #ifdef S_IFLNK if (!glue_lstat(resolved_path->str_text, st)) { if (S_ISLNK(st->st_mode) && ignore_symlinks) { // // This is a symbolic link, and we have been told to // ignore symbolic links. // // If this is the first symlink of this name (i.e. the // shallowest in the view path) remember it, otherwise // simply ignore it. // // Either way, keep looking down the view path. // if (!maybe_pathname) { maybe_statbuf = *st; maybe_pathname = str_copy(resolved_path); maybe_depth = j; } str_free(resolved_path); continue; } if (depth_p) { int depth = j; if (maybe_pathname && maybe_depth == 0) depth |= TOP_LEVEL_SYMLINK; *depth_p = depth; } if (maybe_pathname) str_free(maybe_pathname); trace(("}\n")); return resolved_path; } if (errno != ENOENT) { int errno_old = errno; sub_context_ty sc; sc.errno_setx(errno_old); sc.var_set_string("File_Name", resolved_path); sc.fatal_intl(i18n("lstat $filename: $errno")); // NOTREACHED } #else if (!glue_stat(resolved_path->str_text, st)) { if (depth_p) *depth_p = j; trace(("}\n")); return resolved_path; } if (errno != ENOENT) { int errno_old; errno_old = errno; scp = sub_context_new(); sub_errno_setx(scp, errno_old); sub_var_set_string(scp, "File_Name", resolved_path); fatal_intl(scp, i18n("stat $filename: $errno")); // NOTREACHED } #endif str_free(resolved_path); } if (maybe_pathname) { // // We didn't find a regular file, but we did find // a symlink. Return the symlink. // *st = maybe_statbuf; if (depth_p) *depth_p = maybe_depth; trace(("}\n")); return maybe_pathname; } trace(("}\n")); return 0; } void dir_stack_stat(string_list_ty *stack, string_ty *path, struct stat *st, int *depth_p, int ignore_symlinks) { string_ty *result; trace(("dir_stack_stat(path = \"%s\")\n{\n", path->str_text)); result = dir_stack_find(stack, 0, path, st, depth_p, ignore_symlinks); if (!result) { sub_context_ty *scp; scp = sub_context_new(); sub_errno_setx(scp, ENOENT); sub_var_set_string(scp, "File_Name", path); fatal_intl(scp, i18n("stat $filename: $errno")); // NOTREACHED } str_free(result); trace(("}\n")); } void dir_stack_readdir(string_list_ty *stack, string_ty *path, string_list_ty *result) { size_t j; string_ty *s; string_ty *dir; trace(("dir_stack_readdir(path = \"%s\")\n{\n", path->str_text)); result->clear(); for (j = 0; j < stack->size(); ++j) { dir = (*stack)[j]; s = os_path_cat(dir, path); trace(("s = \"%s\";\n", s->str_text)); if (read_whole_dir__wla(s->str_text, result)) { sub_context_ty *scp; int errno_old; errno_old = errno; if (errno_old == ENOENT) { str_free(s); trace(("mark\n")); continue; } scp = sub_context_new(); sub_errno_setx(scp, errno_old); sub_var_set_string(scp, "File_Name", path); fatal_intl(scp, i18n("read $filename: $errno")); // NOTREACHED } str_free(s); trace(("mark\n")); } trace(("}\n")); } void dir_stack_walk(string_list_ty *stack, string_ty *path, dir_stack_walk_callback_t callback, void *arg, int ignore_symlinks) { struct stat st; string_ty *s; int depth; trace(("dir_stack_walk(path = %p, callback = %p, arg = %p, " "ign = %d)\n{\n", path, callback, arg, ignore_symlinks)); trace_string(path->str_text); dir_stack_stat(stack, path, &st, &depth, ignore_symlinks); switch (st.st_mode & S_IFMT) { case S_IFDIR: { callback(arg, dir_stack_walk_dir_before, path, &st, depth, ignore_symlinks); string_list_ty wl; dir_stack_readdir(stack, path, &wl); trace(("mark\n")); for (size_t j = 0; j < wl.size(); ++j) { s = os_path_cat(path, wl[j]); trace(("s = \"%s\";\n", s->str_text)); dir_stack_walk(stack, s, callback, arg, ignore_symlinks); str_free(s); trace(("mark\n")); } trace(("mark\n")); callback(arg, dir_stack_walk_dir_after, path, &st, depth, ignore_symlinks); trace(("mark\n")); } break; case S_IFREG: trace(("mark\n")); callback(arg, dir_stack_walk_file, path, &st, depth, ignore_symlinks); break; #if defined(S_IFLNK) || defined(S_ISLNK) case S_IFLNK: trace(("mark\n")); callback(arg, dir_stack_walk_symlink, path, &st, depth, ignore_symlinks); break; #endif default: trace(("mark\n")); callback(arg, dir_stack_walk_special, path, &st, depth, ignore_symlinks); break; } trace(("}\n")); } string_ty * dir_stack_relative(string_list_ty *stack, string_ty *path) { size_t j; string_ty *s; trace(("dir_stack_relative(path = \"%s\")\n{\n", path->str_text)); for (j = 0; j < stack->size(); ++j) { s = os_below_dir((*stack)[j], path); if (s) { trace(("return \"%s\";\n", s->str_text)); trace(("}\n")); return s; } } trace(("return NULL;\n")); trace(("}\n")); return 0; } // vim: set ts=8 sw=4 et :