Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / tt / bin / tttar / tttar_file_utils.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
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 $                                                   
28 /*
29  * tttar_file_utils.cc - File utilities for the ToolTalk archive tool.
30  *
31  * Copyright (c) 1990 by Sun Microsystems, Inc.
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #if defined(ultrix)
42 #include <sys/inode.h>
43 #define S_ISLNK(m)     (((m)&IFMT) == IFLNK)
44 #endif
45 #include <dirent.h>
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)
50 #endif
51
52 extern char *_tt_get_realpath(char  *, char *);
53
54 /*
55  * is_child_in() - Is <path> a node in any of the path trees listed?
56  *
57  *      Returns true if, for any string <pathtree> in <paths>,
58  *      a) "<path>" == "<pathtree>", or
59  *      b) "<pathtree>/" is a prefix of "<path>".
60  *
61  */
62 bool_t
63 is_child_in( _Tt_string path, _Tt_string_list_ptr paths )
64 {
65         _Tt_string_list_cursor  path_cursor( paths );
66         while (path_cursor.next()) {
67                 if (is_child_of( path, (*path_cursor))) {
68                         return TRUE;
69                 }
70         }
71         return FALSE;
72 }
73
74 /*
75  * is_child_of() - Is <path> in the path tree given?
76  *
77  *      Returns true if
78  *      a) "<path>" == "<pathtree>", or
79  *      b) "<pathtree>/" is a prefix of "<path>".
80  *
81  */
82 bool_t
83 is_child_of( _Tt_string path, _Tt_string pathtree )
84 {
85         if (pathtree == path) {
86                 return TRUE;
87         }
88         _Tt_string prefix = pathtree.cat( "/" );
89         if ( prefix == path.left( prefix.len())) {
90                 return TRUE;
91         }
92         return FALSE;
93 }
94
95 /*
96  * new_name() - Return the most specific renaming, or an empty string.
97  */
98 _Tt_string
99 new_name( _Tt_string old_name, Lstar_string_map_list_ptr renamings )
100 {
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 );
104
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())
110                         {
111                                 best_renaming = *renaming_cursor;
112                         }
113                 }
114         }
115         /*
116          * If a renaming was found...
117          */
118         if ( best_renaming->old_string().len() > 0) {
119                 /*
120                  * ... the new name will have as its prefix the
121                  * replacement part of the mapping.
122                  */
123                 _new_name = best_renaming->new_string();
124                 /*
125                  * If it was not a perfect match...
126                  */
127                 if (old_name != best_renaming->old_string()) {
128                         /*
129                          * ... we need to tack on whatever is
130                          * unique about old_string.
131                          */
132                         _new_name =
133                             _new_name.cat(
134                                 old_name.right(
135                                       old_name.len()
136                                     - best_renaming->old_string().len()));
137                 }
138         }
139         return _new_name;
140 }
141
142 /*
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.
148  */
149 _Tt_string_list_ptr
150 dir_entries( _Tt_string path, bool_t follow_symlinks )
151 {
152         DIR                    *dirp;
153         _Tt_string_list_ptr     entries(new _Tt_string_list);
154
155         if (! follow_symlinks) {
156                 struct stat     lstat_buf;
157                 int             lstat_status;
158
159                 lstat_status = lstat( (char *)path, &lstat_buf );
160                 if (( lstat_status == 0) && S_ISLNK(lstat_buf.st_mode)) {
161                         return entries;
162                 }
163         }
164         dirp = opendir( (char *)path );
165         if (dirp == NULL) {
166                 return entries;
167         }
168         while (TRUE) {
169                 struct dirent  *entry;
170                 _Tt_string      epath;
171                 _Tt_string      epath_slash;
172                 _Tt_string      ename;
173
174                 entry = readdir( dirp );
175                 if (entry == NULL) {
176                         break;
177                 }
178                 ename = entry->d_name;
179                 if ((ename == ".") || (ename == "..")) {
180                         continue;
181                 }
182                 epath_slash = path.cat( "/" );
183                 epath = epath_slash.cat( entry->d_name );
184                 entries->push( epath );
185         }
186         if (closedir( dirp ) != 0) {
187                 fprintf( stderr, "%s: closedir(\"%s\"): %s\n",
188                          our_process_name, (char *)path, strerror(errno) );
189         }
190         return entries;
191
192 } /* dir_entries() */
193
194 /*
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.
198  */
199 _Tt_string_list_ptr
200 realtrees( _Tt_string_list_ptr paths, bool_t follow_symlinks )
201 {
202         _Tt_string_list_ptr     realpaths(new _Tt_string_list);
203         _Tt_string_list_cursor  path_cursor( paths );
204
205         while (path_cursor.next()) {
206                 char            resolved_path_buf[ MAXPATHLEN+1 ];
207                 char           *resolved_path;
208                 _Tt_string      abs_path;
209                 _Tt_string      path;
210                 struct stat     lstat_buf;
211                 int             lstat_status;
212
213                 path = (*path_cursor);
214                 lstat_status = lstat( (char *)path, &lstat_buf );
215                 if ( lstat_status != 0) {
216                         /*
217                          * ToolTalk objects can be associated
218                          * with paths that don't exist.
219                          */
220                         if (errno != ENOENT) {
221                                 fprintf( stderr,
222                                          "%s: lstat(\"%s\"): %s\n",
223                                          our_process_name,
224                                          (char *)path, strerror(errno) );
225                                 continue;
226                         } else {
227                                 resolved_path =
228                                         _tt_get_realpath( (char *)path,
229                                                   resolved_path_buf );
230                         }
231                 } else if (S_ISLNK(lstat_buf.st_mode)) {
232                         if (follow_symlinks) {
233                                 resolved_path = _tt_get_realpath( (char *)path,
234                                                           resolved_path_buf );
235                         } else {
236                                 /*
237                                  * Use the absolute path of the
238                                  * symlink instead of the path of the
239                                  * linked file.
240                                  */
241                                 char *dir = dirname( (char *)path );
242                                 char *base = basename( (char *)path );
243                                 resolved_path = _tt_get_realpath( dir,
244                                                           resolved_path_buf );
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 );
250                                 }
251                         }
252                 } else {
253                         resolved_path = _tt_get_realpath( (char *)path,
254                                                   resolved_path_buf );
255                 }
256                 if (resolved_path != NULL) {
257                         abs_path = resolved_path;
258                 } else {
259                         if (errno == ENOENT) {
260                                 /*
261                                  * XXX: We need to figure out here what the
262                                  * realpath would be if the file existed.
263                                  */
264                         }
265                         fprintf( stderr, "%s: %s: %s\n",
266                                  our_process_name,
267                                  (char *)path, strerror(errno) );
268                         continue;
269                 }
270                 realpaths->push( abs_path );
271                 if (follow_symlinks) {
272                         append_real_subtrees( realpaths, abs_path );
273                 }
274         }
275         return realpaths;
276
277 } /* realtrees() */
278
279 /*
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>.
283  */
284 void
285 append_real_subtrees( _Tt_string_list_ptr realtrees, _Tt_string path )
286 {
287         struct stat     stat_buf;
288         DIR            *dirp;
289
290         if (stat( (char *)path, &stat_buf ) != 0) {
291                 fprintf( stderr, "%s: stat(\"%s\"): %s\n",
292                          our_process_name, (char *)path, strerror(errno) );
293                 return;
294         }
295         if (! S_ISDIR(stat_buf.st_mode)) {
296                 return;
297         }
298         dirp = opendir( (char *)path );
299         if (dirp == NULL) {
300                 fprintf( stderr, "%s: realpath(\"%s\"): %s\n",
301                          our_process_name, (char *)path, strerror(errno) );
302                 perror( NULL );
303                 return;
304         }
305         while (TRUE) {
306                 struct dirent  *entry;
307                 struct stat     lstat_buf;
308                 _Tt_string      epath;
309                 _Tt_string      epath_slash;
310                 _Tt_string      ename;
311
312                 entry = readdir( dirp );
313                 if (entry == NULL) {
314                         break;
315                 }
316                 ename = entry->d_name;
317                 if ((ename == ".") || (ename == "..")) {
318                         continue;
319                 }
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,
325                                  strerror(errno) );
326                         perror( NULL );
327                         continue;
328                 }
329                 if (stat( (char *)epath, &stat_buf ) != 0) {
330                         fprintf( stderr, "%s: stat(\"%s\"): %s\n",
331                                  our_process_name, (char *)epath,
332                                  strerror(errno) );
333                         perror( NULL );
334                         continue;
335                 }
336                 if (S_ISDIR(stat_buf.st_mode)) {
337                         if (S_ISLNK(lstat_buf.st_mode)) {
338                                 char    rpath_buf[ MAXPATHLEN+1 ];
339                                 char   *rpath;
340
341                                 rpath = _tt_get_realpath( (char *)epath, rpath_buf );
342                                 if (rpath == NULL) {
343                                         fprintf( stderr,
344                                                  "%s: realpath(\"%s\"): %s\n",
345                                                  our_process_name,(char *)epath,
346                                                  strerror(errno) );
347                                 } else {
348                                         _Tt_string rp( rpath );
349                                         realtrees->push( rp );
350                                 }
351                         }
352                         append_real_subtrees( realtrees, epath );
353                 }
354         }
355         if (closedir( dirp ) != 0) {
356                 fprintf( stderr, "%s: closedir(\"%s\"): %s\n",
357                          our_process_name, (char *)path, strerror(errno) );
358         }
359
360 } /* append_real_subtrees() */
361
362 /*
363  * basename() - Return the last component of a pathname.
364  */
365 char *basename( char *pathname ) {
366         char *the_basename;
367         
368         the_basename = strrchr( pathname, '/' );
369         if (the_basename == NULL) {
370                 the_basename = pathname;
371         } else {
372                 the_basename++;         // Don't want the '/'
373         }
374         return the_basename;
375 }
376
377 /*
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.
381  */
382 char *dirname( char *pathname ) {
383         char *the_basename;
384         char *the_dirname;
385         
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';
391         } else {
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';
397         }
398         return the_dirname;
399 }