diff options
Diffstat (limited to 'dir.c')
-rw-r--r-- | dir.c | 199 |
1 files changed, 142 insertions, 57 deletions
@@ -142,6 +142,32 @@ downcase (const char *filename) #ifdef VMS +static char * +downcase_inplace(char *filename) +{ + char *name; + name = filename; + while (*name != '\0') + { + *name = tolower ((unsigned char)*name); + ++name; + } + return filename; +} + +#ifndef _USE_STD_STAT +/* VMS 8.2 fixed the VMS stat output to have unique st_dev and st_ino + when _USE_STD_STAT is used on the compile line. + + Prior to _USE_STD_STAT support, the st_dev is a pointer to thread + static memory containing the device of the last filename looked up. + + Todo: find out if the ino_t still needs to be faked on a directory. + */ + +/* Define this if the older VMS_INO_T is needed */ +#define VMS_INO_T 1 + static int vms_hash (const char *name) { @@ -200,6 +226,10 @@ vmsstat_dir (const char *name, struct stat *st) return 0; } + +# define stat(__path, __sbuf) vmsstat_dir (__path, __sbuf) + +#endif /* _USE_STD_STAT */ #endif /* VMS */ /* Hash table of directories. */ @@ -225,7 +255,7 @@ struct directory_contents # define FS_NTFS 0x2 # define FS_UNKNOWN 0x4 #else -# ifdef VMS +# ifdef VMS_INO_T ino_t ino[3]; # else ino_t ino; @@ -246,7 +276,7 @@ directory_contents_hash_1 (const void *key_0) ISTRING_HASH_1 (key->path_key, hash); hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) key->ctime; #else -# ifdef VMS +# ifdef VMS_INO_T hash = (((unsigned int) key->dev << 4) ^ ((unsigned int) key->ino[0] + (unsigned int) key->ino[1] @@ -269,7 +299,7 @@ directory_contents_hash_2 (const void *key_0) ISTRING_HASH_2 (key->path_key, hash); hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime; #else -# ifdef VMS +# ifdef VMS_INO_T hash = (((unsigned int) key->dev << 4) ^ ~((unsigned int) key->ino[0] + (unsigned int) key->ino[1] @@ -308,7 +338,7 @@ directory_contents_hash_cmp (const void *xv, const void *yv) if (result) return result; #else -# ifdef VMS +# ifdef VMS_INO_T result = MAKECMP(x->ino[0], y->ino[0]); if (result) return result; @@ -419,13 +449,6 @@ find_directory (const char *name) struct directory **dir_slot; struct directory dir_key; -#ifdef VMS - if ((*name == '.') && (*(name+1) == 0)) - name = "[]"; - else - name = vmsify (name,1); -#endif - dir_key.name = name; dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key); dir = *dir_slot; @@ -439,7 +462,12 @@ find_directory (const char *name) dir = xmalloc (sizeof (struct directory)); #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) - dir->name = strcache_add_len (downcase (name), p - name); + /* Todo: Why is this only needed on VMS? */ + { + char *lname = downcase_inplace (xstrdup (name)); + dir->name = strcache_add_len (lname, p - name); + free (lname); + } #else dir->name = strcache_add_len (name, p - name); #endif @@ -447,9 +475,7 @@ find_directory (const char *name) /* The directory is not in the name hash table. Find its device and inode numbers, and look it up by them. */ -#ifdef VMS - r = vmsstat_dir (name, &st); -#elif defined(WINDOWS32) +#if defined(WINDOWS32) { char tem[MAXPATHLEN], *tstart, *tend; @@ -492,7 +518,7 @@ find_directory (const char *name) dc_key.path_key = w32_path = w32ify (name, 1); dc_key.ctime = st.st_ctime; #else -# ifdef VMS +# ifdef VMS_INO_T dc_key.ino[0] = st.st_ino[0]; dc_key.ino[1] = st.st_ino[1]; dc_key.ino[2] = st.st_ino[2]; @@ -537,7 +563,7 @@ find_directory (const char *name) else dc->fs_flags = FS_UNKNOWN; #else -# ifdef VMS +# ifdef VMS_INO_T dc->ino[0] = st.st_ino[0]; dc->ino[1] = st.st_ino[1]; dc->ino[2] = st.st_ino[2]; @@ -602,11 +628,6 @@ dir_contents_file_exists_p (struct directory_contents *dir, if (filename != 0) _fnlwr (filename); /* lower case for FAT drives */ #endif - -#ifdef VMS - filename = vmsify (filename,0); -#endif - if (filename != 0) { struct dirfile dirfile_key; @@ -679,7 +700,9 @@ dir_contents_file_exists_p (struct directory_contents *dir, } #if defined(VMS) && defined(HAVE_DIRENT_H) - /* In VMS we get file versions too, which have to be stripped off */ + /* In VMS we get file versions too, which have to be stripped off. + Some versions of VMS return versions on Unix files even when + the feature option to strip them is set. */ { char *p = strrchr (d->d_name, ';'); if (p) @@ -703,7 +726,8 @@ dir_contents_file_exists_p (struct directory_contents *dir, { df = xmalloc (sizeof (struct dirfile)); #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) - df->name = strcache_add_len (downcase (d->d_name), len); + /* TODO: Why is this only needed on VMS? */ + df->name = strcache_add_len (downcase_inplace (d->d_name), len); #else df->name = strcache_add_len (d->d_name, len); #endif @@ -734,6 +758,15 @@ dir_contents_file_exists_p (struct directory_contents *dir, int dir_file_exists_p (const char *dirname, const char *filename) { +#ifdef VMS + if ((filename != NULL) && (dirname != NULL)) + { + int want_vmsify; + want_vmsify = (strpbrk (dirname, ":<[") != NULL); + if (want_vmsify) + filename = vmsify (filename, 0); + } +#endif return dir_contents_file_exists_p (find_directory (dirname)->contents, filename); } @@ -752,14 +785,24 @@ file_exists_p (const char *name) return ar_member_date (name) != (time_t) -1; #endif + dirend = strrchr (name, '/'); #ifdef VMS - dirend = strrchr (name, ']'); if (dirend == 0) - dirend = strrchr (name, ':'); + { + dirend = strrchr (name, ']'); + dirend == NULL ? dirend : dirend++; + } if (dirend == 0) - return dir_file_exists_p ("[]", name); -#else /* !VMS */ - dirend = strrchr (name, '/'); + { + dirend = strrchr (name, '>'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == 0) + { + dirend = strrchr (name, ':'); + dirend == NULL ? dirend : dirend++; + } +#endif /* VMS */ #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { @@ -774,10 +817,9 @@ file_exists_p (const char *name) if (dirend == 0) #ifndef _AMIGA return dir_file_exists_p (".", name); -#else /* !VMS && !AMIGA */ +#else /* !AMIGA */ return dir_file_exists_p ("", name); #endif /* AMIGA */ -#endif /* VMS */ slash = dirend; if (dirend == name) @@ -796,7 +838,13 @@ file_exists_p (const char *name) p[dirend - name] = '\0'; dirname = p; } - return dir_file_exists_p (dirname, slash + 1); +#ifdef VMS + if (*slash == '/') + slash++; +#else + slash++; +#endif + return dir_file_exists_p (dirname, slash); } /* Mark FILENAME as 'impossible' for 'file_impossible_p'. @@ -811,16 +859,25 @@ file_impossible (const char *filename) struct directory *dir; struct dirfile *new; -#ifdef VMS - dirend = strrchr (p, ']'); - if (dirend == 0) - dirend = strrchr (p, ':'); - dirend++; - if (dirend == (char *)1) - dir = find_directory ("[]"); -#else dirend = strrchr (p, '/'); -# ifdef HAVE_DOS_PATHS +#ifdef VMS + if (dirend == NULL) + { + dirend = strrchr (p, ']'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == NULL) + { + dirend = strrchr (p, '>'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == NULL) + { + dirend = strrchr (p, ':'); + dirend == NULL ? dirend : dirend++; + } +#endif +#ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { const char *bslash = strrchr (p, '\\'); @@ -830,14 +887,13 @@ file_impossible (const char *filename) if (!dirend && p[0] && p[1] == ':') dirend = p + 1; } -# endif /* HAVE_DOS_PATHS */ +#endif /* HAVE_DOS_PATHS */ if (dirend == 0) -# ifdef _AMIGA +#ifdef _AMIGA dir = find_directory (""); -# else /* !VMS && !AMIGA */ +#else /* !AMIGA */ dir = find_directory ("."); -# endif /* AMIGA */ -#endif /* VMS */ +#endif /* AMIGA */ else { const char *dirname; @@ -859,7 +915,14 @@ file_impossible (const char *filename) dirname = cp; } dir = find_directory (dirname); +#ifdef VMS + if (*slash == '/') + filename = p = slash + 1; + else + filename = p = slash; +#else filename = p = slash + 1; +#endif } if (dir->contents == 0) @@ -878,6 +941,7 @@ file_impossible (const char *filename) new = xmalloc (sizeof (struct dirfile)); new->length = strlen (filename); #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) + /* todo: Why is this only needed on VMS? */ new->name = strcache_add_len (downcase (filename), new->length); #else new->name = strcache_add_len (filename, new->length); @@ -895,13 +959,22 @@ file_impossible_p (const char *filename) struct directory_contents *dir; struct dirfile *dirfile; struct dirfile dirfile_key; - #ifdef VMS - dirend = strrchr (filename, ']'); - if (dirend == 0) - dir = find_directory ("[]")->contents; -#else + int want_vmsify = 0; +#endif + dirend = strrchr (filename, '/'); +#ifdef VMS + if (dirend == NULL) + { + want_vmsify = (strpbrk (filename, "]>:^") != NULL); + dirend = strrchr (filename, ']'); + } + if (dirend == NULL && want_vmsify) + dirend = strrchr (filename, '>'); + if (dirend == NULL && want_vmsify) + dirend = strrchr (filename, ':'); +#endif #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { @@ -916,10 +989,9 @@ file_impossible_p (const char *filename) if (dirend == 0) #ifdef _AMIGA dir = find_directory ("")->contents; -#else /* !VMS && !AMIGA */ +#else /* !AMIGA */ dir = find_directory (".")->contents; #endif /* AMIGA */ -#endif /* VMS */ else { const char *dirname; @@ -941,7 +1013,14 @@ file_impossible_p (const char *filename) dirname = cp; } dir = find_directory (dirname)->contents; +#ifdef VMS + if (*slash == '/') + filename = slash + 1; + else + filename = slash; +#else filename = slash + 1; +#endif } if (dir == 0 || dir->dirfiles.ht_vec == 0) @@ -955,7 +1034,8 @@ file_impossible_p (const char *filename) filename = downcase (filename); #endif #ifdef VMS - filename = vmsify (filename, 1); + if (want_vmsify) + filename = vmsify (filename, 1); #endif dirfile_key.name = filename; @@ -1005,7 +1085,7 @@ print_dir_data_base (void) printf (_("# %s (key %s, mtime %d): could not be opened.\n"), dir->name, dir->contents->path_key,dir->contents->mtime); #else /* WINDOWS32 */ -#ifdef VMS +#ifdef VMS_INO_T printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"), dir->name, dir->contents->dev, dir->contents->ino[0], dir->contents->ino[1], @@ -1041,7 +1121,7 @@ print_dir_data_base (void) printf (_("# %s (key %s, mtime %d): "), dir->name, dir->contents->path_key, dir->contents->mtime); #else /* WINDOWS32 */ -#ifdef VMS +#ifdef VMS_INO_T printf (_("# %s (device %d, inode [%d,%d,%d]): "), dir->name, dir->contents->dev, dir->contents->ino[0], dir->contents->ino[1], @@ -1179,9 +1259,14 @@ read_dirstream (__ptr_t stream) * On MS-Windows, stat() "succeeds" for foo/bar/. where foo/bar is a * regular file; fix that here. */ -#if !defined(stat) && !defined(WINDOWS32) +#if !defined(stat) && !defined(WINDOWS32) || defined(VMS) # ifndef VMS int stat (const char *path, struct stat *sbuf); +# else + /* We are done with the fake stat. Go back to the real stat */ +# ifdef stat +# undef stat +# endif # endif # define local_stat stat #else |