relative-path-canonicalization-20061120
[openafs.git] / src / util / dirpath.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #include <stddef.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <limits.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include "assert.h"
24 #include "afsutil.h"
25 #include "fileutil.h"
26 #ifdef AFS_PTHREAD_ENV
27 #include <pthread.h>
28 static pthread_once_t dirInit_once = PTHREAD_ONCE_INIT;
29 #endif
30 #ifdef AFS_NT40_ENV
31 #include <windows.h>
32 #include <WINNT\afssw.h>
33 #endif
34 #ifdef AFS_DARWIN_ENV
35 #include <unistd.h>
36 #endif
37
38 /* local vars */
39 /* static storage for path strings */
40 static char dirPathArray[AFSDIR_PATHSTRING_MAX][AFSDIR_PATH_MAX];
41
42 /* indicate if and how the dirpath module initialized. */
43 static int initFlag = 0;
44 static unsigned int initStatus = 0;
45
46
47 /* storage for dynamically-determined install dir (NT only; long and short) */
48 #ifdef AFS_NT40_ENV
49 static char ntServerInstallDirLong[AFSDIR_PATH_MAX];
50 static char ntServerInstallDirShort[AFSDIR_PATH_MAX];
51 static char ntClientConfigDirLong[AFSDIR_PATH_MAX];
52 static char ntClientConfigDirShort[AFSDIR_PATH_MAX];
53 #endif
54
55 /* storage for local afs server/client paths (top-level) */
56 static char afsSrvDirPath[AFSDIR_PATH_MAX];
57 static char afsClntDirPath[AFSDIR_PATH_MAX];
58
59 /* internal array init function */
60 static void initDirPathArray(void);
61
62 /* Additional macros for ease of use */
63 /* buf is expected to be atleast AFS_PATH_MAX bytes long */
64 #define AFSDIR_SERVER_DIRPATH(buf, dir)  \
65             (void) strcompose(buf, AFSDIR_PATH_MAX, serverPrefix, dir, NULL)
66
67 #define AFSDIR_SERVER_FILEPATH(buf, dir, file)  \
68             (void) strcompose(buf, AFSDIR_PATH_MAX, serverPrefix, dir, "/", file,  NULL)
69
70 #define AFSDIR_CLIENT_DIRPATH(buf, dir)  \
71             (void) strcompose(buf, AFSDIR_PATH_MAX, clientPrefix, dir, NULL)
72
73 #define AFSDIR_CLIENT_FILEPATH(buf, dir, file)  \
74             (void) strcompose(buf, AFSDIR_PATH_MAX,  clientPrefix, dir, "/", file,  NULL)
75
76
77 /* initAFSDirPath() -- External users call this function to initialize
78  * the dirpath module and/or to determine the initialization status.
79  */
80 unsigned int
81 initAFSDirPath(void)
82 {
83     if (initFlag == 0) {        /* not yet init'ed, so initialize */
84 #ifdef AFS_PTHREAD_ENV
85         pthread_once(&dirInit_once, initDirPathArray);
86 #else
87         initDirPathArray();
88 #endif
89     }
90     return initStatus;
91 }
92
93
94 /* initDirPathArray() -- Initializes the afs dir paths for the 
95  *     server and client installations.
96  *
97  *     For NT these are determined dynamically; for Unix they are static.
98  *
99  *     NT NOTE: If a particular component (client/server) is not installed
100  *              then we may not be able to initialize the paths to anything
101  *              meaningful.  In this case the paths are set to the local
102  *              temp directory to avoid later reference to an uninitialized
103  *              variable.  The initStatus flag is set to indicate which
104  *              paths (client/server) initialized properly for callers of
105  *              initAFSDirPath() who would like to know this information.
106  */
107 static void
108 initDirPathArray(void)
109 {
110     char *pathp;
111     const char *clientPrefix = "";
112     const char *serverPrefix = "";
113
114 #ifdef AFS_NT40_ENV
115     char *buf;
116     int status;
117
118     /* get the afs server software installation dir from the registry */
119     if (afssw_GetServerInstallDir(&buf)) {
120         /* failed; server not installed; use temp directory */
121         strcpy(ntServerInstallDirLong, gettmpdir());
122     } else {
123         strcpy(ntServerInstallDirLong, buf);
124         free(buf);
125         initStatus |= AFSDIR_SERVER_PATHS_OK;
126     }
127     FilepathNormalize(ntServerInstallDirLong);
128     status =
129         GetShortPathName(ntServerInstallDirLong, ntServerInstallDirShort,
130                          AFSDIR_PATH_MAX);
131     if (status == 0 || status > AFSDIR_PATH_MAX) {
132         /* can't convert path to short version; just use long version */
133         strcpy(ntServerInstallDirShort, ntServerInstallDirLong);
134     }
135     FilepathNormalize(ntServerInstallDirShort);
136
137     /* get the afs client configuration directory (/usr/vice/etc equivalent) */
138     if (afssw_GetClientInstallDir(&buf)) {
139         /* failed */
140         status = GetWindowsDirectory(ntClientConfigDirLong, AFSDIR_PATH_MAX);
141         if (status == 0 || status > AFSDIR_PATH_MAX) {
142             /* failed to get canonical Windows directory; use temp directory */
143             strcpy(ntClientConfigDirLong, gettmpdir());
144         } else {
145             initStatus |= AFSDIR_CLIENT_PATHS_OK;
146         }
147     } else {
148         strcpy(ntClientConfigDirLong, buf);
149         free(buf);
150         initStatus |= AFSDIR_CLIENT_PATHS_OK;
151     }
152     FilepathNormalize(ntClientConfigDirLong);
153
154     status =
155         GetShortPathName(ntClientConfigDirLong, ntClientConfigDirShort,
156                          AFSDIR_PATH_MAX);
157     if (status == 0 || status > AFSDIR_PATH_MAX) {
158         /* can't convert path to short version; just use long version */
159         strcpy(ntClientConfigDirShort, ntClientConfigDirLong);
160     }
161     FilepathNormalize(ntClientConfigDirShort);
162     clientPrefix = ntClientConfigDirShort;
163
164     /* setup the root server directory path (/usr/afs equivalent) */
165     strcpy(afsSrvDirPath, ntServerInstallDirShort);
166     strcat(afsSrvDirPath, AFSDIR_CANONICAL_SERVER_AFS_DIRPATH);
167
168     /* there is no root client directory path (/usr/vice equivalent) */
169     afsClntDirPath[0] = '\0';
170
171     /* setup top level dirpath (/usr equivalent); valid for server ONLY */
172     strcpy(dirPathArray[AFSDIR_USR_DIRPATH_ID], ntServerInstallDirShort);
173     serverPrefix = ntServerInstallDirShort;
174     strcat(dirPathArray[AFSDIR_USR_DIRPATH_ID], AFSDIR_CANONICAL_USR_DIRPATH);
175
176 #else /* AFS_NT40_ENV */
177     /* setup the root server directory path */
178     strcpy(afsSrvDirPath, AFSDIR_CANONICAL_SERVER_AFS_DIRPATH);
179
180     /* setup the root client directory path */
181 #ifdef AFS_DARWIN_ENV
182     if (access(AFSDIR_ALTERNATE_CLIENT_VICE_DIRPATH, F_OK) == 0)
183         strcpy(afsClntDirPath, AFSDIR_ALTERNATE_CLIENT_VICE_DIRPATH);
184     else
185 #endif
186         strcpy(afsClntDirPath, AFSDIR_CANONICAL_CLIENT_VICE_DIRPATH);
187
188     /* setup top level dirpath; valid for both server and client */
189     strcpy(dirPathArray[AFSDIR_USR_DIRPATH_ID], AFSDIR_CANONICAL_USR_DIRPATH);
190
191     initStatus |= (AFSDIR_CLIENT_PATHS_OK | AFSDIR_SERVER_PATHS_OK);
192 #endif /* AFS_NT40_ENV */
193
194     /* now initialize various dir and file paths exported by dirpath module */
195
196     /* server dir paths */
197     strcpy(dirPathArray[AFSDIR_SERVER_AFS_DIRPATH_ID], afsSrvDirPath);
198
199     pathp = dirPathArray[AFSDIR_SERVER_ETC_DIRPATH_ID];
200     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_SERVER_ETC_DIR);
201
202     pathp = dirPathArray[AFSDIR_SERVER_BIN_DIRPATH_ID];
203     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_SERVER_BIN_DIR);
204
205     pathp = dirPathArray[AFSDIR_SERVER_CORES_DIRPATH_ID];
206     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_CORES_DIR);
207
208     pathp = dirPathArray[AFSDIR_SERVER_DB_DIRPATH_ID];
209     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_DB_DIR);
210
211     pathp = dirPathArray[AFSDIR_SERVER_LOGS_DIRPATH_ID];
212     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_LOGS_DIR);
213
214     pathp = dirPathArray[AFSDIR_SERVER_LOCAL_DIRPATH_ID];
215     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_LOCAL_DIR);
216
217     pathp = dirPathArray[AFSDIR_SERVER_BACKUP_DIRPATH_ID];
218     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_BACKUP_DIR);
219
220     pathp = dirPathArray[AFSDIR_SERVER_MIGRATE_DIRPATH_ID];
221     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_MIGR_DIR);
222
223     pathp = dirPathArray[AFSDIR_SERVER_BIN_FILE_DIRPATH_ID];
224     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_BIN_FILE_DIR);
225
226     /* client dir path */
227 #ifdef AFS_NT40_ENV
228     strcpy(dirPathArray[AFSDIR_CLIENT_VICE_DIRPATH_ID],
229            "/NoUsrViceDirectoryOnWindows");
230     strcpy(dirPathArray[AFSDIR_CLIENT_ETC_DIRPATH_ID],
231            ntClientConfigDirShort);
232 #else
233     strcpy(dirPathArray[AFSDIR_CLIENT_VICE_DIRPATH_ID], afsClntDirPath);
234
235     pathp = dirPathArray[AFSDIR_CLIENT_ETC_DIRPATH_ID];
236 #ifdef AFS_DARWIN_ENV
237     if (access(AFSDIR_ALTERNATE_CLIENT_ETC_DIR, F_OK) == 0)
238         AFSDIR_CLIENT_DIRPATH(pathp, AFSDIR_ALTERNATE_CLIENT_ETC_DIR);
239     else
240 #endif
241         AFSDIR_CLIENT_DIRPATH(pathp, AFSDIR_CLIENT_ETC_DIR);
242 #endif /* AFS_NT40_ENV */
243
244     /* server file paths */
245     pathp = dirPathArray[AFSDIR_SERVER_THISCELL_FILEPATH_ID];
246     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR,
247                            AFSDIR_THISCELL_FILE);
248
249     pathp = dirPathArray[AFSDIR_SERVER_CELLSERVDB_FILEPATH_ID];
250     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR,
251                            AFSDIR_CELLSERVDB_FILE);
252
253     pathp = dirPathArray[AFSDIR_SERVER_NOAUTH_FILEPATH_ID];
254     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_NOAUTH_FILE);
255
256     pathp = dirPathArray[AFSDIR_SERVER_BUDBLOG_FILEPATH_ID];
257     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_BUDBLOG_FILE);
258
259     pathp = dirPathArray[AFSDIR_SERVER_TAPECONFIG_FILEPATH_ID];
260     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BACKUP_DIR, AFSDIR_TAPECONFIG_FILE);
261
262     pathp = dirPathArray[AFSDIR_SERVER_KALOGDB_FILEPATH_ID];
263     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_KALOGDB_FILE);
264
265     pathp = dirPathArray[AFSDIR_SERVER_KALOG_FILEPATH_ID];
266     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_KALOG_FILE);
267
268     pathp = dirPathArray[AFSDIR_SERVER_KADB_FILEPATH_ID];
269     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_DB_DIR, AFSDIR_KADB_FILE);
270
271     pathp = dirPathArray[AFSDIR_SERVER_NTPD_FILEPATH_ID];
272     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_BIN_DIR, AFSDIR_NTPD_FILE);
273
274     pathp = dirPathArray[AFSDIR_SERVER_PRDB_FILEPATH_ID];
275     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_DB_DIR, AFSDIR_PRDB_FILE);
276
277     pathp = dirPathArray[AFSDIR_SERVER_PTLOG_FILEPATH_ID];
278     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_PTLOG_FILE);
279
280     pathp = dirPathArray[AFSDIR_SERVER_KCONF_FILEPATH_ID];
281     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_KCONF_FILE);
282
283     pathp = dirPathArray[AFSDIR_SERVER_VLDB_FILEPATH_ID];
284     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_DB_DIR, AFSDIR_VLDB_FILE);
285
286     pathp = dirPathArray[AFSDIR_SERVER_VLOG_FILEPATH_ID];
287     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_VLOG_FILE);
288
289     pathp = dirPathArray[AFSDIR_SERVER_CORELOG_FILEPATH_ID];
290     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_CORE_FILE);
291
292     pathp = dirPathArray[AFSDIR_SERVER_SLVGLOG_FILEPATH_ID];
293     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_SLVGLOG_FILE);
294
295     pathp = dirPathArray[AFSDIR_SERVER_SALSRVLOG_FILEPATH_ID];
296     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_SALSRVLOG_FILE);
297
298     pathp = dirPathArray[AFSDIR_SERVER_SALVAGER_FILEPATH_ID];
299     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_BIN_DIR,
300                            AFSDIR_SALVAGER_FILE);
301
302     pathp = dirPathArray[AFSDIR_SERVER_SALSRV_FILEPATH_ID];
303     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_BIN_DIR,
304                            AFSDIR_SALSRV_FILE);
305
306     pathp = dirPathArray[AFSDIR_SERVER_SLVGLOCK_FILEPATH_ID];
307     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_SLVGLOCK_FILE);
308
309     pathp = dirPathArray[AFSDIR_SERVER_KEY_FILEPATH_ID];
310     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_KEY_FILE);
311
312     pathp = dirPathArray[AFSDIR_SERVER_ULIST_FILEPATH_ID];
313     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_ULIST_FILE);
314
315     pathp = dirPathArray[AFSDIR_SERVER_BOZCONF_FILEPATH_ID];
316     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BOSCONFIG_DIR, AFSDIR_BOZCONF_FILE);
317
318     pathp = dirPathArray[AFSDIR_SERVER_BOZCONFNEW_FILEPATH_ID];
319     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BOSCONFIG_DIR,
320                            AFSDIR_BOZCONFNEW_FILE);
321
322     pathp = dirPathArray[AFSDIR_SERVER_BOZLOG_FILEPATH_ID];
323     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_BOZLOG_FILE);
324
325     pathp = dirPathArray[AFSDIR_SERVER_BOZINIT_FILEPATH_ID];
326     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BOSCONFIG_DIR, AFSDIR_BOZINIT_FILE);
327
328     pathp = dirPathArray[AFSDIR_SERVER_BOSVR_FILEPATH_ID];
329     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BOSSERVER_DIR, AFSDIR_BOSVR_FILE);
330
331     pathp = dirPathArray[AFSDIR_SERVER_VOLSERLOG_FILEPATH_ID];
332     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_VOLSERLOG_FILE);
333
334     pathp = dirPathArray[AFSDIR_SERVER_ROOTVOL_FILEPATH_ID];
335     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_ROOTVOL_FILE);
336
337     pathp = dirPathArray[AFSDIR_SERVER_HOSTDUMP_FILEPATH_ID];
338     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_HOSTDUMP_FILE);
339
340     pathp = dirPathArray[AFSDIR_SERVER_CLNTDUMP_FILEPATH_ID];
341     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_CLNTDUMP_FILE);
342
343     pathp = dirPathArray[AFSDIR_SERVER_CBKDUMP_FILEPATH_ID];
344     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_CBKDUMP_FILE);
345
346     pathp = dirPathArray[AFSDIR_SERVER_OLDSYSID_FILEPATH_ID];
347     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_OLDSYSID_FILE);
348
349     pathp = dirPathArray[AFSDIR_SERVER_SYSID_FILEPATH_ID];
350     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_SYSID_FILE);
351
352     pathp = dirPathArray[AFSDIR_SERVER_FILELOG_FILEPATH_ID];
353     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_FILELOG_FILE);
354
355     pathp = dirPathArray[AFSDIR_SERVER_AUDIT_FILEPATH_ID];
356     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_AUDIT_FILE);
357
358     pathp = dirPathArray[AFSDIR_SERVER_NETINFO_FILEPATH_ID];
359     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_NETINFO_FILE);
360
361     pathp = dirPathArray[AFSDIR_SERVER_NETRESTRICT_FILEPATH_ID];
362     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_NETRESTRICT_FILE);
363
364     pathp = dirPathArray[AFSDIR_SERVER_WEIGHTING_CONSTANTS_FILEPATH_ID];
365     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_MIGR_DIR,
366                            AFSDIR_WEIGHTINGCONST_FILE);
367
368     pathp = dirPathArray[AFSDIR_SERVER_THRESHOLD_CONSTANTS_FILEPATH_ID];
369     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_MIGR_DIR,
370                            AFSDIR_THRESHOLDCONST_FILE);
371
372     pathp = dirPathArray[AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID];
373     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_MIGR_DIR, AFSDIR_MIGRATE_LOGNAME);
374
375     pathp = dirPathArray[AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID];
376     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_KRB_EXCL_FILE);
377
378     pathp = dirPathArray[AFSDIR_SERVER_FSSTATE_FILEPATH_ID];
379     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_FSSTATE_FILE);
380
381     /* client file paths */
382 #ifdef AFS_NT40_ENV
383     strcpy(dirPathArray[AFSDIR_CLIENT_THISCELL_FILEPATH_ID],
384            "/NoUsrViceEtcThisCellFileOnWindows");
385     sprintf(dirPathArray[AFSDIR_CLIENT_CELLSERVDB_FILEPATH_ID], "%s/%s",
386             ntClientConfigDirShort, AFSDIR_CELLSERVDB_FILE_NTCLIENT);
387     strcpy(dirPathArray[AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID],
388            "/NoCellAliasOnWindows");
389 #else
390     pathp = dirPathArray[AFSDIR_CLIENT_THISCELL_FILEPATH_ID];
391     AFSDIR_CLIENT_FILEPATH(pathp, AFSDIR_CLIENT_ETC_DIR,
392                            AFSDIR_THISCELL_FILE);
393
394     pathp = dirPathArray[AFSDIR_CLIENT_CELLSERVDB_FILEPATH_ID];
395     AFSDIR_CLIENT_FILEPATH(pathp, AFSDIR_CLIENT_ETC_DIR,
396                            AFSDIR_CELLSERVDB_FILE);
397
398     pathp = dirPathArray[AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID];
399     AFSDIR_CLIENT_FILEPATH(pathp, AFSDIR_CLIENT_ETC_DIR,
400                            AFSDIR_CELLALIAS_FILE);
401 #endif /* AFS_NT40_ENV */
402
403     pathp = dirPathArray[AFSDIR_CLIENT_NETINFO_FILEPATH_ID];
404     AFSDIR_CLIENT_FILEPATH(pathp, AFSDIR_CLIENT_ETC_DIR, AFSDIR_NETINFO_FILE);
405
406     pathp = dirPathArray[AFSDIR_CLIENT_NETRESTRICT_FILEPATH_ID];
407     AFSDIR_CLIENT_FILEPATH(pathp, AFSDIR_CLIENT_ETC_DIR,
408                            AFSDIR_NETRESTRICT_FILE);
409
410     initFlag = 1;               /* finished dirpath initialization */
411     return;
412 }
413
414 /* getDirPath - returns a const char pointer to the requested string
415  * from the internal path array.
416  * string_id - index into the path array 
417  */
418 const char *
419 getDirPath(afsdir_id_t string_id)
420 {
421     /* check if the array has been initialized */
422     if (initFlag == 0) {        /* no it's not, so initialize */
423 #ifdef AFS_PTHREAD_ENV
424         pthread_once(&dirInit_once, initDirPathArray);
425 #else
426         initDirPathArray();
427 #endif
428     }
429     return (const char *)dirPathArray[string_id];
430 }
431
432 /*
433  * LocalizePathHead() -- Make path relative to local part
434  *
435  * ConstructLocalPath takes a path and a directory that path should
436  * be considered relative to.  There are two possible cases:
437  *
438  * The path is an absolute path.  In this case, the relative path
439  * is ignored.  We check the path for a prefix that represents a
440  * canonical path, and if one is found, we adjust the path to remove
441  * the prefix and adjust the directory to which it should be
442  * considered relative to be the local version of that canonical path.
443  *
444  * The path is a relative path.  In this case, we check to see if the
445  * directory to which it is relative represents a canonical path, and
446  * if so, we adjust that directory to be the local version of that
447  * canonical path.  The relative path itself is left unchanged.
448  */
449
450 /* The following array  maps cannonical parts to local parts.  It
451  * might  seem reasonable to  simply construct an array in parallel to
452  * dirpatharray  but it turns out you don't want translations for all
453  * local paths.
454 */
455
456 struct canonmapping {
457     const char *canonical;
458     const char *local;
459 };
460 static struct canonmapping CanonicalTranslations[] = {
461     {AFSDIR_CANONICAL_SERVER_ETC_DIRPATH, AFSDIR_SERVER_ETC_DIR},
462     {AFSDIR_CANONICAL_SERVER_LOGS_DIRPATH, AFSDIR_LOGS_DIR},
463     {AFSDIR_CANONICAL_SERVER_LOCAL_DIRPATH, AFSDIR_LOCAL_DIR},
464     {AFSDIR_CANONICAL_SERVER_BIN_DIRPATH, AFSDIR_SERVER_BIN_DIR},
465     {NULL, NULL}
466 };
467
468 static void
469 LocalizePathHead(const char **path, const char **relativeTo)
470 {
471      struct canonmapping *map;
472  
473      if (**path == '/') {
474          for (map = CanonicalTranslations; map->local != NULL; map++) {
475              int canonlength = strlen(map->canonical);
476              if (strncmp(*path, map->canonical, canonlength) == 0) {
477                  (*path) += canonlength;
478                  if (**path == '/')
479                      (*path)++;
480                  *relativeTo = map->local;
481                  return;
482              }
483          }
484      } else {
485          for (map = CanonicalTranslations; map->local != NULL; map++) {
486              if (strcmp(*relativeTo, map->canonical) == 0) {
487                  *relativeTo = map->local;
488                  return;
489              }
490          }
491      }
492 }
493
494
495 #ifdef AFS_NT40_ENV
496 /* NT version of ConstructLocalPath() */
497
498 /*
499  * ConstructLocalPath() --  Convert a canonical (wire-format) path to a fully
500  *     specified local path.  Upon successful completion, *fullPathBufp is
501  *     set to an allocated buffer containing the fully specified local path
502  *     constructed from the cpath argument.
503  *
504  *     On NT, path construction proceeds as follows:
505  *         1) If cpath is fully qualified (i.e., starts with 'X:/') then the
506  *            path returned is equivalent to cpath.
507  *         2) If cpath begins with a drive letter but is not fully qualified,
508  *            i.e., it is drive relative, then the function fails with EINVAL.
509  *         3) If cpath begins with '/' (or '\') then the path returned is the
510  *            concatenation  AFS-server-install-dir + cpath after translating for localization.
511  *         4) Otherwise the path returned is the concatenation
512  *            AFS-server-install-dir + relativeTo + cpath.
513  *
514  *     Leading whitespace in cpath is ignored; the constructed path is
515  *     normalized (FilepathNormalize()).
516  *
517  * RETURN CODES: 0 if successful; errno code otherwise.
518  */
519 int
520 ConstructLocalPath(const char *cpath, const char *relativeTo,
521                    char **fullPathBufp)
522 {
523     int status = 0;
524     char *newPath = NULL;
525
526     if (initFlag == 0) {        /* dirpath module not yet initialized */
527 #ifdef AFS_PTHREAD_ENV
528         pthread_once(&dirInit_once, initDirPathArray);
529 #else
530         initDirPathArray();
531 #endif
532     }
533
534     *fullPathBufp = NULL;
535
536     while (isspace(*cpath)) {
537         cpath++;
538     }
539
540     LocalizePathHead(&cpath, &relativeTo);
541     if ((((*cpath >= 'a') && (*cpath <= 'z'))
542          || ((*cpath >= 'A') && (*cpath <= 'Z'))) && (*(cpath + 1) == ':')) {
543
544         /* cpath has a leading drive letter */
545         if ((*(cpath + 2) != '/') && (*(cpath + 2) != '\\')) {
546             /* drive letter relative path; this is not allowed */
547             status = EINVAL;
548         } else {
549             /* fully qualified path; just make a copy */
550             newPath = (char *)malloc(strlen(cpath) + 1);
551             if (!newPath) {
552                 status = ENOMEM;
553             } else {
554                 (void)strcpy(newPath, cpath);
555             }
556         }
557
558     } else {
559         /* cpath has NO leading drive letter; make relative to install dir */
560         size_t pathSize = strlen(ntServerInstallDirShort) + 2;
561
562         if ((*cpath == '/') || (*cpath == '\\')) {
563             /* construct path relative to install directory only */
564             pathSize += strlen(cpath);
565
566             newPath = (char *)malloc(pathSize);
567             if (!newPath) {
568                 status = ENOMEM;
569             } else {
570                 sprintf(newPath, "%s/%s", ntServerInstallDirShort, cpath);
571             }
572         } else {
573             /* construct path relative to 'relativeTo' (and install dir) */
574             pathSize += strlen(relativeTo) + 1 + strlen(cpath);
575
576             newPath = (char *)malloc(pathSize);
577             if (!newPath) {
578                 status = ENOMEM;
579             } else {
580                 sprintf(newPath, "%s/%s/%s", ntServerInstallDirShort,
581                         relativeTo, cpath);
582             }
583         }
584     }
585
586     if (status == 0) {
587         FilepathNormalize(newPath);
588
589         /* return buffer containing fully specified path */
590         *fullPathBufp = newPath;
591     }
592
593     return status;
594 }
595
596 #else
597 /* Unix version of ConstructLocalPath() */
598
599 /*
600  * ConstructLocalPath() --  Convert a canonical (wire-format) path to a fully
601  *     specified local path.  Upon successful completion, *fullPathBufp is
602  *     set to an allocated buffer containing the fully specified local path
603  *     constructed from the cpath argument.
604  *
605  *     On Unix, path construction proceeds as follows:
606  *         1) If cpath begins with '/' then the path returned is equivalent
607  *            to cpath.
608  *         2) Otherwise the path returned is the concatenation
609  *            relativeTo + cpath.
610  *
611  *     Leading whitespace in cpath is ignored; the constructed path is
612  *     normalized (FilepathNormalize()).
613  *
614  * RETURN CODES: 0 if successful; errno code otherwise.
615  */
616 int
617 ConstructLocalPath(const char *cpath, const char *relativeTo,
618                    char **fullPathBufp)
619 {
620     int status = 0;
621     char *newPath = NULL;
622
623     if (initFlag == 0) {        /* dirpath module not yet initialized */
624 #ifdef AFS_PTHREAD_ENV
625         pthread_once(&dirInit_once, initDirPathArray);
626 #else
627         initDirPathArray();
628 #endif
629     }
630
631     *fullPathBufp = NULL;
632
633     while (isspace(*cpath)) {
634         cpath++;
635     }
636
637     LocalizePathHead(&cpath, &relativeTo);
638     if (*cpath == '/') {
639         newPath = (char *)malloc(strlen(cpath) + 1);
640         if (!newPath) {
641             status = ENOMEM;
642         } else {
643             strcpy(newPath, cpath);
644         }
645     } else {
646         newPath = (char *)malloc(strlen(relativeTo) + 1 + strlen(cpath) + 1);
647         if (!newPath) {
648             status = ENOMEM;
649         } else {
650             sprintf(newPath, "%s/%s", relativeTo, cpath);
651         }
652     }
653
654     if (status == 0) {
655         FilepathNormalize(newPath);
656
657         /* return buffer containing fully specified path */
658         *fullPathBufp = newPath;
659     }
660
661     return status;
662 }
663 #endif /* AFS_NT40_ENV */
664
665
666 /*
667  * ConstructLocalBinPath() -- A convenience wrapper for ConstructLocalPath()
668  *     that specifies the canonical AFS server binary directory as the relative
669  *     directory.
670  */
671 int
672 ConstructLocalBinPath(const char *cpath, char **fullPathBufp)
673 {
674     return ConstructLocalPath(cpath, AFSDIR_SERVER_BIN_DIRPATH,
675                               fullPathBufp);
676 }
677
678
679 /*
680  * ConstructLocalLogPath() -- A convenience wrapper for ConstructLocalPath()
681  *     that specifies the canonical AFS server logs directory as the relative
682  *     directory.
683  */
684 int
685 ConstructLocalLogPath(const char *cpath, char **fullPathBufp)
686 {
687     return ConstructLocalPath(cpath, AFSDIR_SERVER_LOGS_DIRPATH,
688                               fullPathBufp);
689 }