Remove Unixware and openserver support
[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 libraries 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
49 extern char *_tt_get_realpath(char  *, char *);
50
51 /*
52  * is_child_in() - Is <path> a node in any of the path trees listed?
53  *
54  *      Returns true if, for any string <pathtree> in <paths>,
55  *      a) "<path>" == "<pathtree>", or
56  *      b) "<pathtree>/" is a prefix of "<path>".
57  *
58  */
59 bool_t
60 is_child_in( _Tt_string path, _Tt_string_list_ptr paths )
61 {
62         _Tt_string_list_cursor  path_cursor( paths );
63         while (path_cursor.next()) {
64                 if (is_child_of( path, (*path_cursor))) {
65                         return TRUE;
66                 }
67         }
68         return FALSE;
69 }
70
71 /*
72  * is_child_of() - Is <path> in the path tree given?
73  *
74  *      Returns true if
75  *      a) "<path>" == "<pathtree>", or
76  *      b) "<pathtree>/" is a prefix of "<path>".
77  *
78  */
79 bool_t
80 is_child_of( _Tt_string path, _Tt_string pathtree )
81 {
82         if (pathtree == path) {
83                 return TRUE;
84         }
85         _Tt_string prefix = pathtree.cat( "/" );
86         if ( prefix == path.left( prefix.len())) {
87                 return TRUE;
88         }
89         return FALSE;
90 }
91
92 /*
93  * new_name() - Return the most specific renaming, or an empty string.
94  */
95 _Tt_string
96 new_name( _Tt_string old_name, Lstar_string_map_list_ptr renamings )
97 {
98         _Tt_string                      _new_name;
99         Lstar_string_map_ptr            best_renaming(new Lstar_string_map);
100         Lstar_string_map_list_cursor    renaming_cursor( renamings );
101
102         while (renaming_cursor.next()) {
103                 _Tt_string rename_pattern = (*renaming_cursor)->old_string();
104                 if (is_child_of( old_name, rename_pattern )) {
105                         if (   rename_pattern.len()
106                              > best_renaming->old_string().len())
107                         {
108                                 best_renaming = *renaming_cursor;
109                         }
110                 }
111         }
112         /*
113          * If a renaming was found...
114          */
115         if ( best_renaming->old_string().len() > 0) {
116                 /*
117                  * ... the new name will have as its prefix the
118                  * replacement part of the mapping.
119                  */
120                 _new_name = best_renaming->new_string();
121                 /*
122                  * If it was not a perfect match...
123                  */
124                 if (old_name != best_renaming->old_string()) {
125                         /*
126                          * ... we need to tack on whatever is
127                          * unique about old_string.
128                          */
129                         _new_name =
130                             _new_name.cat(
131                                 old_name.right(
132                                       old_name.len()
133                                     - best_renaming->old_string().len()));
134                 }
135         }
136         return _new_name;
137 }
138
139 /*
140  * dir_entries() - Return a new list of paths, with one entry for each
141  *      entry in the directory <path>, each entry consisting of
142  *      <path> appended by a slash and the name of the entry.
143  *      Returns an empty list if <path> is not a directory.
144  *      If !follow_symlinks, returns an empty list if <path> is a symlink.
145  */
146 _Tt_string_list_ptr
147 dir_entries( _Tt_string path, bool_t follow_symlinks )
148 {
149         DIR                    *dirp;
150         _Tt_string_list_ptr     entries(new _Tt_string_list);
151
152         if (! follow_symlinks) {
153                 struct stat     lstat_buf;
154                 int             lstat_status;
155
156                 lstat_status = lstat( (char *)path, &lstat_buf );
157                 if (( lstat_status == 0) && S_ISLNK(lstat_buf.st_mode)) {
158                         return entries;
159                 }
160         }
161         dirp = opendir( (char *)path );
162         if (dirp == NULL) {
163                 return entries;
164         }
165         while (TRUE) {
166                 struct dirent  *entry;
167                 _Tt_string      epath;
168                 _Tt_string      epath_slash;
169                 _Tt_string      ename;
170
171                 entry = readdir( dirp );
172                 if (entry == NULL) {
173                         break;
174                 }
175                 ename = entry->d_name;
176                 if ((ename == ".") || (ename == "..")) {
177                         continue;
178                 }
179                 epath_slash = path.cat( "/" );
180                 epath = epath_slash.cat( entry->d_name );
181                 entries->push( epath );
182         }
183         if (closedir( dirp ) != 0) {
184                 fprintf( stderr, "%s: closedir(\"%s\"): %s\n",
185                          our_process_name, (char *)path, strerror(errno) );
186         }
187         return entries;
188
189 } /* dir_entries() */
190
191 /*
192  * realtrees() - Return a new absolutized list of the paths given.
193  *      If follow_symlinks, then recurse on any directories listed and
194  *      put the realpath of the other end of the symlink onto the list.
195  */
196 _Tt_string_list_ptr
197 realtrees( _Tt_string_list_ptr paths, bool_t follow_symlinks )
198 {
199         _Tt_string_list_ptr     realpaths(new _Tt_string_list);
200         _Tt_string_list_cursor  path_cursor( paths );
201
202         while (path_cursor.next()) {
203                 char            resolved_path_buf[ MAXPATHLEN+1 ];
204                 char           *resolved_path;
205                 _Tt_string      abs_path;
206                 _Tt_string      path;
207                 struct stat     lstat_buf;
208                 int             lstat_status;
209
210                 path = (*path_cursor);
211                 lstat_status = lstat( (char *)path, &lstat_buf );
212                 if ( lstat_status != 0) {
213                         /*
214                          * ToolTalk objects can be associated
215                          * with paths that don't exist.
216                          */
217                         if (errno != ENOENT) {
218                                 fprintf( stderr,
219                                          "%s: lstat(\"%s\"): %s\n",
220                                          our_process_name,
221                                          (char *)path, strerror(errno) );
222                                 continue;
223                         } else {
224                                 resolved_path =
225                                         _tt_get_realpath( (char *)path,
226                                                   resolved_path_buf );
227                         }
228                 } else if (S_ISLNK(lstat_buf.st_mode)) {
229                         if (follow_symlinks) {
230                                 resolved_path = _tt_get_realpath( (char *)path,
231                                                           resolved_path_buf );
232                         } else {
233                                 /*
234                                  * Use the absolute path of the
235                                  * symlink instead of the path of the
236                                  * linked file.
237                                  */
238                                 char *dir = dirname( (char *)path );
239                                 char *base = basename( (char *)path );
240                                 resolved_path = _tt_get_realpath( dir,
241                                                           resolved_path_buf );
242                                 if (resolved_path != NULL) {
243                                         strcat( resolved_path_buf, "/" );
244                                         int len = strlen( resolved_path_buf );
245                                         strncat( resolved_path_buf,
246                                                  base, MAXPATHLEN - len );
247                                 }
248                                 free(dir);
249                         }
250                 } else {
251                         resolved_path = _tt_get_realpath( (char *)path,
252                                                   resolved_path_buf );
253                 }
254                 if (resolved_path != NULL) {
255                         abs_path = resolved_path;
256                 } else {
257                         if (errno == ENOENT) {
258                                 /*
259                                  * XXX: We need to figure out here what the
260                                  * realpath would be if the file existed.
261                                  */
262                         }
263                         fprintf( stderr, "%s: %s: %s\n",
264                                  our_process_name,
265                                  (char *)path, strerror(errno) );
266                         continue;
267                 }
268                 realpaths->push( abs_path );
269                 if (follow_symlinks) {
270                         append_real_subtrees( realpaths, abs_path );
271                 }
272         }
273         return realpaths;
274
275 } /* realtrees() */
276
277 /*
278  * append_real_subtrees() - If <path> is a directory, add to <realtrees>
279  *      any directories it contains links to, and recurse on both
280  *      these and any other real directories in <path>.
281  */
282 void
283 append_real_subtrees( _Tt_string_list_ptr realtrees, _Tt_string path )
284 {
285         struct stat     stat_buf;
286         DIR            *dirp;
287
288         if (stat( (char *)path, &stat_buf ) != 0) {
289                 fprintf( stderr, "%s: stat(\"%s\"): %s\n",
290                          our_process_name, (char *)path, strerror(errno) );
291                 return;
292         }
293         if (! S_ISDIR(stat_buf.st_mode)) {
294                 return;
295         }
296         dirp = opendir( (char *)path );
297         if (dirp == NULL) {
298                 fprintf( stderr, "%s: realpath(\"%s\"): %s\n",
299                          our_process_name, (char *)path, strerror(errno) );
300                 perror( NULL );
301                 return;
302         }
303         while (TRUE) {
304                 struct dirent  *entry;
305                 struct stat     lstat_buf;
306                 _Tt_string      epath;
307                 _Tt_string      epath_slash;
308                 _Tt_string      ename;
309
310                 entry = readdir( dirp );
311                 if (entry == NULL) {
312                         break;
313                 }
314                 ename = entry->d_name;
315                 if ((ename == ".") || (ename == "..")) {
316                         continue;
317                 }
318                 epath_slash = path.cat( "/" );
319                 epath = epath_slash.cat( entry->d_name );
320                 if (lstat( (char *)epath, &lstat_buf ) != 0) {
321                         fprintf( stderr, "%s: lstat(\"%s\"): %s\n",
322                                  our_process_name, (char *)epath,
323                                  strerror(errno) );
324                         perror( NULL );
325                         continue;
326                 }
327                 if (stat( (char *)epath, &stat_buf ) != 0) {
328                         fprintf( stderr, "%s: stat(\"%s\"): %s\n",
329                                  our_process_name, (char *)epath,
330                                  strerror(errno) );
331                         perror( NULL );
332                         continue;
333                 }
334                 if (S_ISDIR(stat_buf.st_mode)) {
335                         if (S_ISLNK(lstat_buf.st_mode)) {
336                                 char    rpath_buf[ MAXPATHLEN+1 ];
337                                 char   *rpath;
338
339                                 rpath = _tt_get_realpath( (char *)epath, rpath_buf );
340                                 if (rpath == NULL) {
341                                         fprintf( stderr,
342                                                  "%s: realpath(\"%s\"): %s\n",
343                                                  our_process_name,(char *)epath,
344                                                  strerror(errno) );
345                                 } else {
346                                         _Tt_string rp( rpath );
347                                         realtrees->push( rp );
348                                 }
349                         }
350                         append_real_subtrees( realtrees, epath );
351                 }
352         }
353         if (closedir( dirp ) != 0) {
354                 fprintf( stderr, "%s: closedir(\"%s\"): %s\n",
355                          our_process_name, (char *)path, strerror(errno) );
356         }
357
358 } /* append_real_subtrees() */
359
360 /*
361  * basename() - Return the last component of a pathname.
362  */
363 #if !defined(linux)
364 char *basename( char *pathname ) {
365         char *the_basename;
366         
367         the_basename = strrchr( pathname, '/' );
368         if (the_basename == NULL) {
369                 the_basename = pathname;
370         } else {
371                 the_basename++;         // Don't want the '/'
372         }
373         return the_basename;
374 }
375 #endif
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 }