/* Utility and Unix shadow routines for XEmacs on Windows NT. Copyright (C) 1994, 1995 Free Software Foundation, Inc. This file is part of XEmacs. XEmacs is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. XEmacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with XEmacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */ /* Adapted for XEmacs by David Hobley */ /* Sync'ed with Emacs 19.34.6 by Marc Paquette */ /* Adapted to fpTeX 0.4 by Fabrice Popineau */ #include /* #### This is an evil dirty hack. We must get rid of it. Word "munging" is not in XEmacs lexicon. - kkm */ /* Internal MSVC data and functions for low-level descriptor munging */ #if (_MSC_VER == 900) extern char _osfile[]; #endif extern int __cdecl _set_osfhnd (int fd, long h); extern int __cdecl _free_osfhnd (int fd); #if 0 /* parallel array of private info on file handles */ typedef struct { unsigned flags; HANDLE hnd; child_process * cp; } filedesc; /* parallel array of private info on file handles */ filedesc fd_info [ MAXDESC ]; #endif /* Global referenced by various functions. */ volume_info_data volume_info; /* Vector to indicate which drives are local and fixed (for which cached data never expires). */ static BOOL fixed_drives[26]; /* Consider cached volume information to be stale if older than 10s, at least for non-local drives. Info for fixed drives is never stale. */ #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' ) #define VOLINFO_STILL_VALID( root_dir, info ) \ ( ( isalpha (root_dir[0]) && \ fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \ || GetTickCount () - info->timestamp < 10000 ) /* Cache support functions. */ /* Simple linked list with linear search is sufficient. */ static volume_info_data *volume_cache = NULL; static volume_info_data * lookup_volume_info (char * root_dir) { volume_info_data * info; for (info = volume_cache; info; info = info->next) if (stricmp (info->root_dir, root_dir) == 0) break; return info; } static void add_volume_info (char * root_dir, volume_info_data * info) { info->root_dir = xstrdup (root_dir); info->next = volume_cache; volume_cache = info; } /* Wrapper for GetVolumeInformation, which uses caching to avoid performance penalty (~2ms on 486 for local drives, 7.5ms for local cdrom drive, ~5-10ms or more for remote drives on LAN). */ volume_info_data * GetCachedVolumeInformation (char * root_dir) { volume_info_data * info; char default_root[ MAX_PATH ]; /* NULL for root_dir means use root from current directory. */ if (root_dir == NULL) { if (GetCurrentDirectory (MAX_PATH, default_root) == 0) return NULL; _parse_root (default_root, &root_dir); *root_dir = 0; root_dir = default_root; } /* Local fixed drives can be cached permanently. Removable drives cannot be cached permanently, since the volume name and serial number (if nothing else) can change. Remote drives should be treated as if they are removable, since there is no sure way to tell whether they are or not. Also, the UNC association of drive letters mapped to remote volumes can be changed at any time (even by other processes) without notice. As a compromise, so we can benefit from caching info for remote volumes, we use a simple expiry mechanism to invalidate cache entries that are more than ten seconds old. */ #if 0 /* No point doing this, because WNetGetConnection is even slower than GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW, GetDriveType is about the only call of this type which does not involve network access, and so is extremely quick). */ /* Map drive letter to UNC if remote. */ if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] ) { char remote_name[ 256 ]; char drive[3] = { root_dir[0], ':' }; if (WNetGetConnection (drive, remote_name, sizeof (remote_name)) == NO_ERROR) /* do something */ ; } #endif info = lookup_volume_info (root_dir); if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info)) { char name[ 256 ]; DWORD serialnum; DWORD maxcomp; DWORD flags; char type[ 256 ]; /* Info is not cached, or is stale. */ if (!GetVolumeInformation (root_dir, name, sizeof (name), &serialnum, &maxcomp, &flags, type, sizeof (type))) return NULL; /* Cache the volume information for future use, overwriting existing entry if present. */ if (info == NULL) { info = (volume_info_data *) xmalloc (sizeof (volume_info_data)); add_volume_info (root_dir, info); } else { free (info->name); free (info->type); } info->name = xstrdup (name); info->serialnum = serialnum; info->maxcomp = maxcomp; info->flags = flags; info->type = xstrdup (type); info->timestamp = GetTickCount (); } return info; } /* Get information on the volume where name is held; set path pointer to start of pathname in name (past UNC header\volume header if present). */ int get_volume_info (const char * name, const char ** pPath) { char temp[MAX_PATH]; char *rootname = NULL; /* default to current volume */ volume_info_data * info; if (name == NULL) return FALSE; /* find the root name of the volume if given */ if (isalpha (name[0]) && name[1] == ':') { rootname = temp; temp[0] = *name++; temp[1] = *name++; temp[2] = '\\'; temp[3] = 0; } else if (IS_DIR_SEP (name[0]) && IS_DIR_SEP (name[1])) { char *str = temp; int slashes = 4; rootname = temp; do { if (IS_DIR_SEP (*name) && --slashes == 0) break; *str++ = *name++; } while ( *name ); *str++ = '\\'; *str = 0; } if (pPath) *pPath = name; info = GetCachedVolumeInformation (rootname); if (info != NULL) { /* Set global referenced by other functions. */ volume_info = *info; return TRUE; } return FALSE; } /* Determine if volume is FAT format (ie. only supports short 8.3 names); also set path pointer to start of pathname in name. */ int is_fat_volume (const char * name, const char ** pPath) { if (get_volume_info (name, pPath)) return (volume_info.maxcomp == 12); return FALSE; }