2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
24 //%% (c) Copyright 1993, 1994 International Business Machines Corp.
25 //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
26 //%% (c) Copyright 1993, 1994 Novell, Inc.
27 //%% $XConsortium: tttar_file_utils.C /main/3 1995/10/20 17:00:26 rswiston $
29 * tttar_file_utils.cc - File utilities for the ToolTalk archive tool.
31 * Copyright (c) 1990 by Sun Microsystems, Inc.
38 #include <sys/param.h>
39 #include <sys/types.h>
42 #include <sys/inode.h>
43 #define S_ISLNK(m) (((m)&IFMT) == IFLNK)
46 #include "tttar_utils.h"
47 #include "tttar_file_utils.h"
48 #if defined(OPT_BUG_USL) || defined(OPT_BUG_UXP)
49 #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
52 extern char *_tt_get_realpath(char *, char *);
55 * is_child_in() - Is <path> a node in any of the path trees listed?
57 * Returns true if, for any string <pathtree> in <paths>,
58 * a) "<path>" == "<pathtree>", or
59 * b) "<pathtree>/" is a prefix of "<path>".
63 is_child_in( _Tt_string path, _Tt_string_list_ptr paths )
65 _Tt_string_list_cursor path_cursor( paths );
66 while (path_cursor.next()) {
67 if (is_child_of( path, (*path_cursor))) {
75 * is_child_of() - Is <path> in the path tree given?
78 * a) "<path>" == "<pathtree>", or
79 * b) "<pathtree>/" is a prefix of "<path>".
83 is_child_of( _Tt_string path, _Tt_string pathtree )
85 if (pathtree == path) {
88 _Tt_string prefix = pathtree.cat( "/" );
89 if ( prefix == path.left( prefix.len())) {
96 * new_name() - Return the most specific renaming, or an empty string.
99 new_name( _Tt_string old_name, Lstar_string_map_list_ptr renamings )
101 _Tt_string _new_name;
102 Lstar_string_map_ptr best_renaming(new Lstar_string_map);
103 Lstar_string_map_list_cursor renaming_cursor( renamings );
105 while (renaming_cursor.next()) {
106 _Tt_string rename_pattern = (*renaming_cursor)->old_string();
107 if (is_child_of( old_name, rename_pattern )) {
108 if ( rename_pattern.len()
109 > best_renaming->old_string().len())
111 best_renaming = *renaming_cursor;
116 * If a renaming was found...
118 if ( best_renaming->old_string().len() > 0) {
120 * ... the new name will have as its prefix the
121 * replacement part of the mapping.
123 _new_name = best_renaming->new_string();
125 * If it was not a perfect match...
127 if (old_name != best_renaming->old_string()) {
129 * ... we need to tack on whatever is
130 * unique about old_string.
136 - best_renaming->old_string().len()));
143 * dir_entries() - Return a new list of paths, with one entry for each
144 * entry in the directory <path>, each entry consisting of
145 * <path> appended by a slash and the name of the entry.
146 * Returns an empty list if <path> is not a directory.
147 * If !follow_symlinks, returns an empty list if <path> is a symlink.
150 dir_entries( _Tt_string path, bool_t follow_symlinks )
153 _Tt_string_list_ptr entries(new _Tt_string_list);
155 if (! follow_symlinks) {
156 struct stat lstat_buf;
159 lstat_status = lstat( (char *)path, &lstat_buf );
160 if (( lstat_status == 0) && S_ISLNK(lstat_buf.st_mode)) {
164 dirp = opendir( (char *)path );
169 struct dirent *entry;
171 _Tt_string epath_slash;
174 entry = readdir( dirp );
178 ename = entry->d_name;
179 if ((ename == ".") || (ename == "..")) {
182 epath_slash = path.cat( "/" );
183 epath = epath_slash.cat( entry->d_name );
184 entries->push( epath );
186 if (closedir( dirp ) != 0) {
187 fprintf( stderr, "%s: closedir(\"%s\"): %s\n",
188 our_process_name, (char *)path, strerror(errno) );
192 } /* dir_entries() */
195 * realtrees() - Return a new absolutized list of the paths given.
196 * If follow_symlinks, then recurse on any directories listed and
197 * put the realpath of the other end of the symlink onto the list.
200 realtrees( _Tt_string_list_ptr paths, bool_t follow_symlinks )
202 _Tt_string_list_ptr realpaths(new _Tt_string_list);
203 _Tt_string_list_cursor path_cursor( paths );
205 while (path_cursor.next()) {
206 char resolved_path_buf[ MAXPATHLEN+1 ];
210 struct stat lstat_buf;
213 path = (*path_cursor);
214 lstat_status = lstat( (char *)path, &lstat_buf );
215 if ( lstat_status != 0) {
217 * ToolTalk objects can be associated
218 * with paths that don't exist.
220 if (errno != ENOENT) {
222 "%s: lstat(\"%s\"): %s\n",
224 (char *)path, strerror(errno) );
228 _tt_get_realpath( (char *)path,
231 } else if (S_ISLNK(lstat_buf.st_mode)) {
232 if (follow_symlinks) {
233 resolved_path = _tt_get_realpath( (char *)path,
237 * Use the absolute path of the
238 * symlink instead of the path of the
241 char *dir = dirname( (char *)path );
242 char *base = basename( (char *)path );
243 resolved_path = _tt_get_realpath( dir,
245 if (resolved_path != NULL) {
246 strcat( resolved_path_buf, "/" );
247 int len = strlen( resolved_path_buf );
248 strncat( resolved_path_buf,
249 base, MAXPATHLEN - len );
253 resolved_path = _tt_get_realpath( (char *)path,
256 if (resolved_path != NULL) {
257 abs_path = resolved_path;
259 if (errno == ENOENT) {
261 * XXX: We need to figure out here what the
262 * realpath would be if the file existed.
265 fprintf( stderr, "%s: %s: %s\n",
267 (char *)path, strerror(errno) );
270 realpaths->push( abs_path );
271 if (follow_symlinks) {
272 append_real_subtrees( realpaths, abs_path );
280 * append_real_subtrees() - If <path> is a directory, add to <realtrees>
281 * any directories it contains links to, and recurse on both
282 * these and any other real directories in <path>.
285 append_real_subtrees( _Tt_string_list_ptr realtrees, _Tt_string path )
287 struct stat stat_buf;
290 if (stat( (char *)path, &stat_buf ) != 0) {
291 fprintf( stderr, "%s: stat(\"%s\"): %s\n",
292 our_process_name, (char *)path, strerror(errno) );
295 if (! S_ISDIR(stat_buf.st_mode)) {
298 dirp = opendir( (char *)path );
300 fprintf( stderr, "%s: realpath(\"%s\"): %s\n",
301 our_process_name, (char *)path, strerror(errno) );
306 struct dirent *entry;
307 struct stat lstat_buf;
309 _Tt_string epath_slash;
312 entry = readdir( dirp );
316 ename = entry->d_name;
317 if ((ename == ".") || (ename == "..")) {
320 epath_slash = path.cat( "/" );
321 epath = epath_slash.cat( entry->d_name );
322 if (lstat( (char *)epath, &lstat_buf ) != 0) {
323 fprintf( stderr, "%s: lstat(\"%s\"): %s\n",
324 our_process_name, (char *)epath,
329 if (stat( (char *)epath, &stat_buf ) != 0) {
330 fprintf( stderr, "%s: stat(\"%s\"): %s\n",
331 our_process_name, (char *)epath,
336 if (S_ISDIR(stat_buf.st_mode)) {
337 if (S_ISLNK(lstat_buf.st_mode)) {
338 char rpath_buf[ MAXPATHLEN+1 ];
341 rpath = _tt_get_realpath( (char *)epath, rpath_buf );
344 "%s: realpath(\"%s\"): %s\n",
345 our_process_name,(char *)epath,
348 _Tt_string rp( rpath );
349 realtrees->push( rp );
352 append_real_subtrees( realtrees, epath );
355 if (closedir( dirp ) != 0) {
356 fprintf( stderr, "%s: closedir(\"%s\"): %s\n",
357 our_process_name, (char *)path, strerror(errno) );
360 } /* append_real_subtrees() */
363 * basename() - Return the last component of a pathname.
365 char *basename( char *pathname ) {
368 the_basename = strrchr( pathname, '/' );
369 if (the_basename == NULL) {
370 the_basename = pathname;
372 the_basename++; // Don't want the '/'
378 * dirname() - Return the pathname minus the basename, or "." if the
379 * basename is all there is. Caller is responsible for free()ing
380 * the storage returned.
382 char *dirname( char *pathname ) {
386 the_basename = strrchr( pathname, '/' );
387 if (the_basename == NULL) {
388 the_dirname = (char *)malloc((size_t)(2 * sizeof(char)));
389 the_dirname[0] = '.';
390 the_dirname[1] = '\0';
392 int len = the_basename - pathname;
393 the_dirname = (char *)
394 malloc((size_t)( sizeof(char) * (len + 1)));
395 strncpy( the_dirname, pathname, len );
396 the_dirname[ len ] = '\0';