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 libraries 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: api_filemap.C /main/3 1995/10/23 09:52:27 rswiston $
31 * @(#)api_filemap.C 1.21 95/02/21
33 * Copyright (c) 1990, 1993 by Sun Microsystems, Inc.
35 * THis file implements the api filename mapping calls to map to/from
36 * canonical name formats of the form hostname:pathname to an
37 * absolute pathname of the form /pathname.
41 #include <sys/param.h>
42 #include "api/c/api_filemap.h"
43 #include "db/tt_db_file.h"
45 #include "util/tt_path.h"
46 #include "api/c/tt_c.h"
47 #include "api/c/api_api.h"
48 #include "api/c/api_mp.h"
49 #include "api/c/api_error.h"
50 #include "util/tt_audit.h"
51 #include "util/tt_port.h"
52 #include "util/tt_host_equiv.h"
54 // "magic" (in the /etc/magic sense) prefix for netfile strings
55 #define TT_NETFILE_PREFIX "TTN0"
57 // Include COMPATIBILITY code for earlier CDE snapshots
59 #define CDE_SNAPSHOT_COMPATIBILITY 1
61 char * _tt_host_file_netfile(const char * host, const char * filename);
62 char * _tt_host_netfile_file(const char * host, const char * netfilename);
63 char * _tt_file_netfile(const char * filename);
64 char * _tt_netfile_file(const char * netfilename);
65 static int get_keyword_value(_Tt_string s, const char * keyword,
66 int &start, int &end);
68 /******************************************************************/
69 /* filename mapping API calls implementation. */
70 /******************************************************************/
72 // On the specified host, assemble a netfilename for the specified filename.
74 tt_host_file_netfile(const char * host, const char * filename)
77 Tt_status status = audit.entry("CC", TT_HOST_FILE_NETFILE, host, filename);
80 if (status != TT_OK) {
81 audit.exit((char *)_tt_error_pointer(status));
82 return (char *)_tt_error_pointer(status);
85 result = _tt_host_file_netfile(host, filename);
92 // On the specified host, create a filename for the specified netfilename.
94 tt_host_netfile_file(const char * host, const char * netfilename)
97 Tt_status status = audit.entry("CC", TT_HOST_NETFILE_FILE, host, netfilename);
100 if (status != TT_OK) {
101 audit.exit((char *)_tt_error_pointer(status));
102 return (char *)_tt_error_pointer(status);
105 result = _tt_host_netfile_file(host, netfilename);
112 // On the local host, create a netfilename for the specified filename.
114 tt_file_netfile(const char *filename)
117 Tt_status status = audit.entry("C", TT_FILE_NETFILE, filename);
120 if (status != TT_OK) {
121 audit.exit((char *)_tt_error_pointer(status));
122 return (char *)_tt_error_pointer(status);
125 result = _tt_file_netfile(filename);
132 // On the local host, create a filename for the specified netfilename.
134 tt_netfile_file(const char *netfilename)
137 Tt_status status = audit.entry("C", TT_NETFILE_FILE, netfilename);
140 if (status != TT_OK) {
141 audit.exit((char *)_tt_error_pointer(status));
142 return (char *)_tt_error_pointer(status);
145 result = _tt_netfile_file(netfilename);
154 // 1) Make RPC call to remote host, and on that
155 // host run tt_file_netfile(filename).
157 // 2) Return the result here.
159 _tt_host_file_netfile(const char * host, const char * filename)
162 _Tt_string hostname(host);
163 _Tt_string local_host = _tt_gethostname();
167 // If this is an RPC call to our localhost, do
168 // it directly and don't bother with RPC.
170 _Tt_host_equiv_ptr eq_p = new _Tt_host_equiv;
172 if (eq_p->hostname_equiv(hostname, local_host) == 1) {
174 printf("DEBUG _tt_host_file_netfile: resolving locally.\n");
177 // strdup already done in _tt_netfile_file()
178 return _tt_file_netfile(filename);
181 _Tt_string path(filename);
184 // Connect to dbserver on remote host.
185 _Tt_db_results db_status;
186 _Tt_db_client_ptr h_dbserv = new _Tt_db_client(hostname, db_status);
188 // run _tt_file_netfile() on the remote host.
189 if ((status = _tt_get_api_error(h_dbserv->getConnectionResults(),
190 _TT_API_FILE_MAP)) == TT_OK) {
192 status = _tt_get_api_error(h_dbserv->file_netfile(path, netfile),
196 if (status != TT_OK) {
197 return (char *)_tt_error_pointer(status);
200 #if CDE_SNAPSHOT_COMPATIBILITY
201 // For compatibility with development snapshots of CDE,
202 // if the returned netfile does not start with TT_NETFILE_PREFIX,
205 if (netfile.left(strlen(TT_NETFILE_PREFIX)) != TT_NETFILE_PREFIX) {
207 netfile = TT_NETFILE_PREFIX;
208 netfile = netfile.cat(path);
210 #endif /* CDE_SNAPSHOT_COMPATIBILITY */
212 return _tt_strdup((char *) netfile);
218 // 1) Make RPC call to remote host, and on that
219 // host run tt_netfile_file(netfilename).
221 // 2) Return the result here.
223 _tt_host_netfile_file(const char * host, const char * netfilename)
226 _Tt_string hostname(host);
227 _Tt_string local_host = _tt_gethostname();
231 // If this is an RPC call to our localhost, do
232 // it directly and don't bother with RPC.
234 _Tt_host_equiv_ptr eq_p = new _Tt_host_equiv;
236 if (eq_p->hostname_equiv(hostname, local_host) == 1) {
238 printf("DEBUG _tt_host_netfile_file: resolving locally.\n");
241 // strdup already done in _tt_netfile_file()
242 return _tt_netfile_file(netfilename);
245 _Tt_string path(netfilename);
249 // Connect to dbserver on remote host.
250 _Tt_db_results db_status;
251 _Tt_db_client_ptr h_dbserv = new _Tt_db_client(hostname, db_status);
253 // run _tt_netfile_file() on the remote host.
254 if ((status = _tt_get_api_error(h_dbserv->getConnectionResults(),
255 _TT_API_FILE_MAP)) != TT_OK) {
256 status = status == TT_ERR_PATH ? TT_ERR_NETFILE : status;
257 return (char *)_tt_error_pointer(status);
260 if ((status = _tt_get_api_error(h_dbserv->netfile_file(path, file),
261 _TT_API_FILE_MAP)) == TT_OK) {
262 return _tt_strdup((char *) file);
265 #if CDE_SNAPSHOT_COMPATIBILITY
266 // Mapping failed. It's just possible that it's a dbserver from
267 // an earlier development snapshot which doesn't understand
268 // netfiles with TT_NETFILE_PREFIX in front of them.
271 if (path.left(strlen(TT_NETFILE_PREFIX)) == TT_NETFILE_PREFIX) {
272 path = path.right(path.len()-strlen(TT_NETFILE_PREFIX));
274 if ((status = _tt_get_api_error(h_dbserv->netfile_file(path, file),
275 _TT_API_FILE_MAP)) == TT_OK) {
276 return _tt_strdup((char *) file);
280 #endif /* CDE_SNAPSHOT_COMPATIBILITY */
282 status = status == TT_ERR_PATH ? TT_ERR_NETFILE : status;
283 return (char *)_tt_error_pointer(status);
288 // given a filename in a valid file path format,
289 // i.e. /a/b/..., return a string in the canonical
290 // format of hostname:/x/y/....
293 _tt_file_netfile(const char *filename)
295 _Tt_string path(filename);
299 // Create the canonical filename.
300 _Tt_api_filename_map_ptr mapp = new _Tt_api_filename_map;
301 return _tt_strdup(mapp->set_filename(path));
305 // given a filename in the canonical format, i.e.
306 // hostname:/x/y/.... return a string in the local
307 // file path format, i.e. /a/b/...
310 _tt_netfile_file(const char *netfilename)
312 _Tt_string network_path(netfilename), result;
313 _Tt_api_filename_map_ptr original_mapp = new _Tt_api_filename_map;
314 _Tt_api_filename_map_ptr new_mapp = new _Tt_api_filename_map;
318 // We want to turn the rpath into a local path. We'd prefer
319 // to use the same local path the creator of the netfile used,
320 // if that works and means the same file. We do this by a two
323 // 1) generate a new rpath based on the original lpath.
324 // If the new rpath == the original rpath, use the
327 // 2) If the new rpath isn't the same, then turn
328 // the original rpath into a lpath by trudging through
331 // parse the canonical filename into its' component parts.
332 result = original_mapp->parse_netfilename(network_path);
333 if (result.len() == 0) {
334 return (char *)_tt_error_pointer(TT_ERR_NETFILE);
337 // Do step 1 above: generate new rpath from old lpath.
338 new_mapp->set_filename(original_mapp->lpath_val());
340 _Tt_string host = new_mapp->hostname_val();
341 _Tt_string rpath = new_mapp->rpath_val();
342 _Tt_string lpath = new_mapp->lpath_val();
344 // compare the new rpath with the old rpath.
345 if (host == original_mapp->hostname_val()) {
346 if (rpath == original_mapp->rpath_val()) {
347 return _tt_strdup(original_mapp->lpath_val());
351 // Do step 2 above: convert the original rpath to a local path.
352 result = _tt_network_path_to_local_path(original_mapp->hostname_val().cat(':').cat(original_mapp->rpath_val()));
354 return _tt_strdup(result);
358 /******************************************************************/
359 /* _Tt_api_filename_map class implementation below. */
360 /******************************************************************/
362 // A canonical pathname is of the following form:
363 // "HOST=0-x,RPATH=x-y,LPATH=y-z:HostnameLpathRpath", where
364 // x, y, and z are ASCII representations of the number
365 // which is the position within the character array where
366 // the concatenated strings begin and end.
368 // "pathname" should be an absolute or relative pathname.
369 _Tt_string _Tt_api_filename_map::
370 set_filename(const _Tt_string & filename)
372 _Tt_string absolute_path = filename;
373 _Tt_string tmp_string(MAXPATHLEN * 3);
376 if (filename[0] != '/') {
377 // A relative path, make it absolute.
378 char wd[MAXPATHLEN+1];
380 if (getcwd(wd, sizeof(wd))) {
381 absolute_path = _Tt_string(wd).cat("/").cat(filename);
385 // Now get the network path of the file.
386 tmp_string = _tt_local_network_path(absolute_path);
389 printf("DEBUG set_filename: _tt_local_network_path(%s) returned %s\n",
390 (char *) absolute_path, (char *) tmp_string);
393 _lpath = absolute_path; // what we know the file as.
395 // load hostname and rpath simultaneously
396 _rpath = tmp_string.split(':', _hostname);
398 // construct a canonical pathname
399 _canonical_path = TT_NETFILE_PREFIX;
400 _canonical_path = _canonical_path.cat("HOST=0-").cat(_hostname.len() - 1).cat(',');
404 _canonical_path.cat("RPATH=").cat(i).cat('-').cat(i + _rpath.len() - 1).cat(',');
408 _canonical_path.cat("LPATH=").cat(i).cat('-').cat(i + _lpath.len() - 1).cat(':');
410 _canonical_path = _canonical_path.cat(_hostname).cat(_rpath).cat(_lpath);
413 printf("DEBUG set_filename: _canonical_path == %s\n", (char *) _canonical_path);
416 return _canonical_path;
420 // "canonical_name" is of the format
421 // "TTN0HOST=0-x,RPATH=x-y,LPATH=y-z:HostnameLpathRpath" as described above
422 // If not, parse_netfilename returns (_Tt_string)0.
423 _Tt_string _Tt_api_filename_map::
424 parse_netfilename(const _Tt_string & canonical_name)
426 _Tt_string tmp_string, dummy;
427 int i, h_begin, h_end, l_begin, l_end, r_begin, r_end;
429 // parse the canonical_path.
431 // It's important to do this in a way that is independent of the
432 // order of the keywords, and which ignores any extraneous keywords
433 // which may be introduced later.
435 // A canonical name should start with TT_NETFILE_PREFIX ("TTN0"),
436 // which we ignore. However if CDE_SNAPSHOT_COMPATIBILITY is 1, and
437 // it starts with HOST= it's from
438 // a slightly older version of the code, and we accept that too.
440 i = strlen(TT_NETFILE_PREFIX);
441 if (canonical_name.left(i) == TT_NETFILE_PREFIX) {
442 tmp_string = canonical_name.mid(i, canonical_name.len()-i);
443 #if CDE_SNAPSHOT_COMPATIBILITY
444 } else if (canonical_name.left(5) == "HOST=") {
445 tmp_string = canonical_name;
446 #endif /* CDE_SNAPSHOT_COMPATIBILITY */
448 return (_Tt_string) 0;
451 // All the keyword stuff is before the colon.
453 tmp_string.split(':',tmp_string);
455 if (!(get_keyword_value(tmp_string, "HOST", h_begin, h_end) &&
456 get_keyword_value(tmp_string, "RPATH", r_begin, r_end) &&
457 get_keyword_value(tmp_string, "LPATH", l_begin, l_end)))
459 return (_Tt_string)0;
463 // get the raw data in the canonical_path, and parse out
466 _canonical_path = canonical_name;
469 printf("DEBUG parse_netfilename: _canonical_path == %s\n", (char *) _canonical_path);
472 tmp_string = _canonical_path.split(':', dummy);
474 _hostname = tmp_string.mid(h_begin, h_end - h_begin + 1);
476 _rpath = tmp_string.mid(r_begin, r_end - r_begin + 1);
479 printf("DEBUG parse_netfilename: _rpath == %s\n", (char *) _rpath);
482 _lpath = tmp_string.mid(l_begin, l_end - l_begin + 1);
485 printf("DEBUG parse_netfilename: _lpath == %s\n", (char *) _lpath);
489 return _canonical_path;
493 _Tt_string _Tt_api_filename_map::
496 return _canonical_path;
499 _Tt_string _Tt_api_filename_map::
505 _Tt_string _Tt_api_filename_map::
511 _Tt_string _Tt_api_filename_map::
518 // Find a keyword in the netfile prefix and return the associated start and
519 // end byte offsets. If the keyword is not found, or the string is badly
520 // formed, return 0. Else, if the parsing succeeds, return 1.
521 // The TT_NETFILE_PREFIX and everything from the colon on are assumed
522 // to already be lopped off s.
525 get_keyword_value(_Tt_string s, const char *keyword, int &start, int &end)
527 // It makes the parsing more uniform if we can always expect to
528 // find the keyword preceded by a comma, which is true for all
529 // but the first keyword. So put a comma on the front, and it
530 // will be true for all keywords. Similarly, put a comma
531 // in front of the keyword and an equals sign after it.
532 // Similarly, add a comma at the end of s so even the last
533 // keyword is terminated by one.
540 ts = ts.cat(s).cat(",");
541 tk = tk.cat(keyword).cat("=");
543 if (-1==(i=ts.index(tk))) {
546 // lop off extraneous stuff before the keyword
547 ts = ts.mid(i,ts.len()-i);
548 // lop off the keyword
549 ts = ts.split('=',junk);
550 // lop off extraneous stuff after the comma that terminates
553 i = sscanf((char *)ts, "%d-%d", &start, &end);