tttar_file_utils.C 10.0 KB

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