dvitomp fix from Akira
[mplib] / src / texk / kpathsea / volume.c
1 /* Utility and Unix shadow routines for XEmacs on Windows NT.
2    Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING.  If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20
21
22    Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */
23
24 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */
25 /* Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */
26 /* Adapted to fpTeX 0.4 by Fabrice Popineau <Fabrice.Popineau@supelec.fr> */
27
28 #ifdef __MINGW32__
29
30 #include <kpathsea/config.h>
31 #include <kpathsea/c-proto.h>
32 #include <kpathsea/win32lib.h>
33 #include <kpathsea/lib.h>
34
35 /* #### This is an evil dirty hack. We must get rid of it.
36    Word "munging" is not in XEmacs lexicon. - kkm */
37
38 /* Internal MSVC data and functions for low-level descriptor munging */
39 #if (_MSC_VER == 900)
40 extern char _osfile[];
41 #endif
42 extern int __cdecl _set_osfhnd (int fd, long h);
43 extern int __cdecl _free_osfhnd (int fd);
44
45 #if 0
46 /* parallel array of private info on file handles */
47 typedef struct
48 {
49   unsigned         flags;
50   HANDLE           hnd;
51   child_process *  cp;
52 } filedesc;
53
54 /* parallel array of private info on file handles */
55 filedesc fd_info [ MAXDESC ];
56 #endif
57
58 /* Global referenced by various functions.  */
59 volume_info_data volume_info;
60
61 /* Vector to indicate which drives are local and fixed (for which cached
62    data never expires).  */
63 static BOOL fixed_drives[26];
64
65 /* Consider cached volume information to be stale if older than 10s,
66    at least for non-local drives.  Info for fixed drives is never stale.  */
67 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
68 #define VOLINFO_STILL_VALID( root_dir, info )           \
69   ( ( isalpha (root_dir[0]) &&                          \
70       fixed_drives[ DRIVE_INDEX (root_dir[0]) ] )       \
71     || GetTickCount () - info->timestamp < 10000 )
72
73 /* Cache support functions.  */
74
75 /* Simple linked list with linear search is sufficient.  */
76 static volume_info_data *volume_cache = NULL;
77
78 static volume_info_data *
79 lookup_volume_info (char * root_dir)
80 {
81   volume_info_data * info;
82
83   for (info = volume_cache; info; info = info->next)
84     if (stricmp (info->root_dir, root_dir) == 0)
85       break;
86   return info;
87 }
88
89 static void
90 add_volume_info (char * root_dir, volume_info_data * info)
91 {
92   info->root_dir = xstrdup (root_dir);
93   info->next = volume_cache;
94   volume_cache = info;
95 }
96
97
98 /* Wrapper for GetVolumeInformation, which uses caching to avoid
99    performance penalty (~2ms on 486 for local drives, 7.5ms for local
100    cdrom drive, ~5-10ms or more for remote drives on LAN).  */
101 volume_info_data *
102 GetCachedVolumeInformation (char * root_dir)
103 {
104   volume_info_data * info;
105   char default_root[ MAX_PATH ];
106
107   /* NULL for root_dir means use root from current directory.  */
108   if (root_dir == NULL)
109     {
110       if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
111         return NULL;
112       _parse_root (default_root, &root_dir);
113       *root_dir = 0;
114       root_dir = default_root;
115     }
116
117   /* Local fixed drives can be cached permanently.  Removable drives
118      cannot be cached permanently, since the volume name and serial
119      number (if nothing else) can change.  Remote drives should be
120      treated as if they are removable, since there is no sure way to
121      tell whether they are or not.  Also, the UNC association of drive
122      letters mapped to remote volumes can be changed at any time (even
123      by other processes) without notice.
124    
125      As a compromise, so we can benefit from caching info for remote
126      volumes, we use a simple expiry mechanism to invalidate cache
127      entries that are more than ten seconds old.  */
128
129 #if 0
130   /* No point doing this, because WNetGetConnection is even slower than
131      GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
132      GetDriveType is about the only call of this type which does not
133      involve network access, and so is extremely quick).  */
134
135   /* Map drive letter to UNC if remote. */
136   if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
137     {
138       char remote_name[ 256 ];
139       char drive[3] = { root_dir[0], ':' };
140
141       if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
142           == NO_ERROR)
143         /* do something */ ;
144     }
145 #endif
146
147   info = lookup_volume_info (root_dir);
148
149   if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
150   {
151     char  name[ 256 ];
152   DWORD     serialnum;
153   DWORD     maxcomp;
154   DWORD     flags;
155     char  type[ 256 ];
156
157     /* Info is not cached, or is stale. */
158     if (!GetVolumeInformation (root_dir,
159                                name, sizeof (name),
160                                &serialnum,
161                                &maxcomp,
162                                &flags,
163                                type, sizeof (type)))
164       return NULL;
165
166     /* Cache the volume information for future use, overwriting existing
167        entry if present.  */
168     if (info == NULL)
169       {
170         info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
171         add_volume_info (root_dir, info);
172       }
173     else
174       {
175         free (info->name);
176         free (info->type);
177       }
178
179     info->name = xstrdup (name);
180     info->serialnum = serialnum;
181     info->maxcomp = maxcomp;
182     info->flags = flags;
183     info->type = xstrdup (type);
184     info->timestamp = GetTickCount ();
185   }
186
187   return info;
188 }
189
190 /* Get information on the volume where name is held; set path pointer to
191    start of pathname in name (past UNC header\volume header if present).  */
192 int
193 get_volume_info (const char * name, const char ** pPath)
194 {
195   char temp[MAX_PATH];
196   char *rootname = NULL;  /* default to current volume */
197   volume_info_data * info;
198
199   if (name == NULL)
200     return FALSE;
201
202   /* find the root name of the volume if given */
203   if (isalpha (name[0]) && name[1] == ':')
204     {
205       rootname = temp;
206       temp[0] = *name++;
207       temp[1] = *name++;
208       temp[2] = '\\';
209       temp[3] = 0;
210     }
211   else if (IS_DIR_SEP (name[0]) && IS_DIR_SEP (name[1]))
212     {
213       char *str = temp;
214       int slashes = 4;
215       rootname = temp;
216       do
217         {
218           if (IS_DIR_SEP (*name) && --slashes == 0)
219             break;
220           *str++ = *name++;
221         }
222       while ( *name );
223
224       *str++ = '\\';
225       *str = 0;
226     }
227
228   if (pPath)
229     *pPath = name;
230     
231   info = GetCachedVolumeInformation (rootname);
232   if (info != NULL)
233     {
234       /* Set global referenced by other functions.  */
235       volume_info = *info;
236       return TRUE;
237     }
238   return FALSE;
239 }
240
241 /* Determine if volume is FAT format (ie. only supports short 8.3
242    names); also set path pointer to start of pathname in name.  */
243 int
244 is_fat_volume (const char * name, const char ** pPath)
245 {
246   if (get_volume_info (name, pPath))
247     return (volume_info.maxcomp == 12);
248   return FALSE;
249 }
250
251 #endif