/* Distributed Checksum Clearinghouse * * --C-LICENSE-- * $Revision: 1.31 $ */ #include "dcc_defs.h" DCC_PATH dcc_homedir; int dcc_homedir_len = 2; /* (ensure comparisons fail) */ #ifndef DCC_WIN32 static void trimpath(DCC_PATH *path, const char *tmp) { const char *s; char c, *t, *p; /* trim "//", "/./", "../", "/../", or trailing "/" */ s = tmp; if (s[0] == '.' && s[1] == '/') s += 2; t = path->c; for (;;) { c = *s++; if (c != '/') { *t = c; if (c == '\0') break; ++t; continue; } /* check character after '/' */ c = *s; if (c == '/') /* discard first '/' in "//" */ continue; if (c == '\0' /* discard trailing '/' */ && t != path->c) continue; if (c != '.') { *t++ = '/'; continue; } /* we have seen "/." */ c = *++s; if (c == '/') /* discard "/." in "/./" */ continue; /* trim trailing "/." */ if (c == '\0') continue; if (c != '.' || (*(s+1) != '/' && *(s+1) != '\0')) { *t++ = '/'; *t++ = '.'; continue; } /* we have "/../" or "/..\0", so remove last name in target */ *t = '\0'; p = strrchr(path->c, '/'); if (p) { t = p; if (t == path->c) /* convert "/.." to "/" */ ++t; } else { t = path->c; } ++s; /* advance to '\0' or 2nd '/' */ } /* yield something reasonable if a bunch of "/../" or similar resulted * in a null string */ if (path->c[0] == '\0') { path->c[0] = tmp[0] == '/' ? '/' : '.'; path->c[1] = '\0'; } } #endif /* Make a home directory relative pathname from a file name * and an optional suffix. * An absolute path unrelated to the home directory remains absolute. * The target path can be the input name. */ u_char /* 0=too long */ dcc_fnm2rel(DCC_PATH *new_path, const char *nm, const char *suffix) { #ifdef DCC_WIN32 return dcc_fnm2abs(new_path, nm, suffix); #else DCC_PATH tmp; int i; const char *p, *p1; /* the answer is the input pathname if it is null */ if (!nm || *nm == '\0') { if (new_path->c != nm) new_path->c[0] = '\0'; return 0; } if (suffix || new_path->c == nm) { p = tmp.c; i = snprintf(tmp.c, sizeof(tmp.c), "%s%s", nm, suffix ? suffix : ""); } else { p = nm; i = strlen(p); } if (i >= ISZ(tmp.c)) { /* too long */ if (new_path->c != nm) new_path->c[0] = '\0'; return 0; } if (p[dcc_homedir_len] == '/' && !strncmp(p, dcc_homedir.c, dcc_homedir_len)) { p1 = p + dcc_homedir_len; do { ++p1; } while (*p1 == '/'); if (*p1 != '\0') p = p1; } trimpath(new_path, p); return 1; #endif } /* make pathname from an optional suffix and a file name relative to * a path or the home directory * path and nm can be the same. */ u_char /* 0=too long */ dcc_fnm2abs(DCC_PATH *path, /* put it here */ const char *nm, const char *suffix) { DCC_PATH tmp; int i; #ifdef DCC_WIN32 char *p; DWORD lasterror; #endif /* the answer is "" if the input pathname is null */ if (!nm || *nm == '\0') { path->c[0] = '\0'; return 0; } if (!suffix) suffix = ""; #ifdef DCC_WIN32 i = snprintf(tmp.c, sizeof(tmp), "%s%s", nm, suffix); if (i >= ISZ(tmp)) { path->c[0] = '\0'; return 0; } lasterror = GetLastError(); GetFullPathName(tmp.c, sizeof(tmp), path, &p); SetLastError(lasterror); return 1; #else if (nm[0] == '/' || dcc_homedir.c[0] == '\0') { i = snprintf(tmp.c, sizeof(tmp), "%s%s", nm, suffix); } else { i = snprintf(tmp.c, sizeof(tmp), "%s/%s%s", dcc_homedir.c, nm, suffix); } trimpath(path, tmp.c); if (i >= ISZ(tmp)) { /* too long */ i = strlen(path->c); if (i > ISZ(DCC_PATH)-4) i = ISZ(DCC_PATH)-4; strcpy(&path->c[i], "..."); return 0; } return 1; #endif } /* make an absolute pathname from a file name for printing */ const char * dcc_fnm2abs_msg(DCC_PATH *path, const char *nm) { /* if the path cannot be made absolute without making it too long, * then return the relative (?) name */ if (dcc_fnm2abs(path, nm, 0)) return path->c; return nm; } /* make a relative pathname from a file name that must not be too long */ void dcc_fnm2rel_good(DCC_PATH *path, const char *nm, const char* suffix) { if (!dcc_fnm2rel(path, nm, suffix)) dcc_logbad(EX_DATAERR, "\"%s%s\" is too long", nm, suffix ? suffix : ""); } /* remove initial substring of the home directory */ const char * dcc_path2fnm(const char *path) { const char *p; if (path[dcc_homedir_len] != '/' || strncmp(path, dcc_homedir.c, dcc_homedir_len)) return path; p = path+dcc_homedir_len; do { ++p; } while (*p == '/'); if (*p == '\0') return path; return p; } const char * dcc_fnm_lno(DCC_FNM_LNO_BUF *buf, const char *fnm, int lno) { DCC_PATH tmp; if (!fnm || *fnm == '\0') { buf->b[0] = '\0'; } else { dcc_fnm2abs(&tmp, fnm, ""); snprintf(buf->b, sizeof(buf->b), DCC_FNM_LNO_PAT, lno, tmp.c); } return buf->b; }