1 1.1 christos /* $NetBSD: filesys.c,v 1.1.1.1 2016/01/14 00:11:29 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* filesys.c -- filesystem specific functions. 4 1.1 christos Id: filesys.c,v 1.6 2004/07/30 17:17:40 karl Exp 5 1.1 christos 6 1.1 christos Copyright (C) 1993, 1997, 1998, 2000, 2002, 2003, 2004 Free Software 7 1.1 christos Foundation, Inc. 8 1.1 christos 9 1.1 christos This program is free software; you can redistribute it and/or modify 10 1.1 christos it under the terms of the GNU General Public License as published by 11 1.1 christos the Free Software Foundation; either version 2, or (at your option) 12 1.1 christos any later version. 13 1.1 christos 14 1.1 christos This program is distributed in the hope that it will be useful, 15 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 16 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 1.1 christos GNU General Public License for more details. 18 1.1 christos 19 1.1 christos You should have received a copy of the GNU General Public License 20 1.1 christos along with this program; if not, write to the Free Software 21 1.1 christos Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 1.1 christos 23 1.1 christos Written by Brian Fox (bfox (at) ai.mit.edu). */ 24 1.1 christos 25 1.1 christos #include "info.h" 26 1.1 christos 27 1.1 christos #include "tilde.h" 28 1.1 christos #include "filesys.h" 29 1.1 christos 30 1.1 christos /* Local to this file. */ 31 1.1 christos static char *info_file_in_path (char *filename, char *path); 32 1.1 christos static char *lookup_info_filename (char *filename); 33 1.1 christos static char *info_absolute_file (char *fname); 34 1.1 christos 35 1.1 christos static void remember_info_filename (char *filename, char *expansion); 36 1.1 christos static void maybe_initialize_infopath (void); 37 1.1 christos 38 1.1 christos typedef struct 39 1.1 christos { 40 1.1 christos char *suffix; 41 1.1 christos char *decompressor; 42 1.1 christos } COMPRESSION_ALIST; 43 1.1 christos 44 1.1 christos static char *info_suffixes[] = { 45 1.1 christos ".info", 46 1.1 christos "-info", 47 1.1 christos "/index", 48 1.1 christos ".inf", /* 8+3 file on filesystem which supports long file names */ 49 1.1 christos #ifdef __MSDOS__ 50 1.1 christos /* 8+3 file names strike again... */ 51 1.1 christos ".in", /* for .inz, .igz etc. */ 52 1.1 christos ".i", 53 1.1 christos #endif 54 1.1 christos "", 55 1.1 christos NULL 56 1.1 christos }; 57 1.1 christos 58 1.1 christos static COMPRESSION_ALIST compress_suffixes[] = { 59 1.1 christos { ".gz", "gunzip" }, 60 1.1 christos { ".bz2", "bunzip2" }, 61 1.1 christos { ".z", "gunzip" }, 62 1.1 christos { ".Z", "uncompress" }, 63 1.1 christos { ".Y", "unyabba" }, 64 1.1 christos #ifdef __MSDOS__ 65 1.1 christos { "gz", "gunzip" }, 66 1.1 christos { "z", "gunzip" }, 67 1.1 christos #endif 68 1.1 christos { (char *)NULL, (char *)NULL } 69 1.1 christos }; 70 1.1 christos 71 1.1 christos /* The path on which we look for info files. You can initialize this 72 1.1 christos from the environment variable INFOPATH if there is one, or you can 73 1.1 christos call info_add_path () to add paths to the beginning or end of it. 74 1.1 christos You can call zap_infopath () to make the path go away. */ 75 1.1 christos char *infopath = (char *)NULL; 76 1.1 christos static int infopath_size = 0; 77 1.1 christos 78 1.1 christos /* Expand the filename in PARTIAL to make a real name for this operating 79 1.1 christos system. This looks in INFO_PATHS in order to find the correct file. 80 1.1 christos If it can't find the file, it returns NULL. */ 81 1.1 christos static char *local_temp_filename = (char *)NULL; 82 1.1 christos static int local_temp_filename_size = 0; 83 1.1 christos 84 1.1 christos char * 85 1.1 christos info_find_fullpath (char *partial) 86 1.1 christos { 87 1.1 christos int initial_character; 88 1.1 christos char *temp; 89 1.1 christos 90 1.1 christos filesys_error_number = 0; 91 1.1 christos 92 1.1 christos maybe_initialize_infopath (); 93 1.1 christos 94 1.1 christos if (partial && (initial_character = *partial)) 95 1.1 christos { 96 1.1 christos char *expansion; 97 1.1 christos 98 1.1 christos expansion = lookup_info_filename (partial); 99 1.1 christos 100 1.1 christos if (expansion) 101 1.1 christos return (expansion); 102 1.1 christos 103 1.1 christos /* If we have the full path to this file, we still may have to add 104 1.1 christos various extensions to it. I guess we have to stat this file 105 1.1 christos after all. */ 106 1.1 christos if (IS_ABSOLUTE (partial)) 107 1.1 christos temp = info_absolute_file (partial); 108 1.1 christos else if (initial_character == '~') 109 1.1 christos { 110 1.1 christos expansion = tilde_expand_word (partial); 111 1.1 christos if (IS_ABSOLUTE (expansion)) 112 1.1 christos { 113 1.1 christos temp = info_absolute_file (expansion); 114 1.1 christos free (expansion); 115 1.1 christos } 116 1.1 christos else 117 1.1 christos temp = expansion; 118 1.1 christos } 119 1.1 christos else if (initial_character == '.' && 120 1.1 christos (IS_SLASH (partial[1]) || 121 1.1 christos (partial[1] == '.' && IS_SLASH (partial[2])))) 122 1.1 christos { 123 1.1 christos if (local_temp_filename_size < 1024) 124 1.1 christos local_temp_filename = (char *)xrealloc 125 1.1 christos (local_temp_filename, (local_temp_filename_size = 1024)); 126 1.1 christos #if defined (HAVE_GETCWD) 127 1.1 christos if (!getcwd (local_temp_filename, local_temp_filename_size)) 128 1.1 christos #else /* !HAVE_GETCWD */ 129 1.1 christos if (!getwd (local_temp_filename)) 130 1.1 christos #endif /* !HAVE_GETCWD */ 131 1.1 christos { 132 1.1 christos filesys_error_number = errno; 133 1.1 christos return (partial); 134 1.1 christos } 135 1.1 christos 136 1.1 christos strcat (local_temp_filename, "/"); 137 1.1 christos strcat (local_temp_filename, partial); 138 1.1 christos temp = info_absolute_file (local_temp_filename); /* try extensions */ 139 1.1 christos if (!temp) 140 1.1 christos partial = local_temp_filename; 141 1.1 christos } 142 1.1 christos else 143 1.1 christos temp = info_file_in_path (partial, infopath); 144 1.1 christos 145 1.1 christos if (temp) 146 1.1 christos { 147 1.1 christos remember_info_filename (partial, temp); 148 1.1 christos if (strlen (temp) > (unsigned int) local_temp_filename_size) 149 1.1 christos local_temp_filename = (char *) xrealloc 150 1.1 christos (local_temp_filename, 151 1.1 christos (local_temp_filename_size = (50 + strlen (temp)))); 152 1.1 christos strcpy (local_temp_filename, temp); 153 1.1 christos free (temp); 154 1.1 christos return (local_temp_filename); 155 1.1 christos } 156 1.1 christos } 157 1.1 christos return (partial); 158 1.1 christos } 159 1.1 christos 160 1.1 christos /* Scan the list of directories in PATH looking for FILENAME. If we find 161 1.1 christos one that is a regular file, return it as a new string. Otherwise, return 162 1.1 christos a NULL pointer. */ 163 1.1 christos static char * 164 1.1 christos info_file_in_path (char *filename, char *path) 165 1.1 christos { 166 1.1 christos struct stat finfo; 167 1.1 christos char *temp_dirname; 168 1.1 christos int statable, dirname_index; 169 1.1 christos 170 1.1 christos /* Reject ridiculous cases up front, to prevent infinite recursion 171 1.1 christos later on. E.g., someone might say "info '(.)foo'"... */ 172 1.1 christos if (!*filename || STREQ (filename, ".") || STREQ (filename, "..")) 173 1.1 christos return NULL; 174 1.1 christos 175 1.1 christos dirname_index = 0; 176 1.1 christos 177 1.1 christos while ((temp_dirname = extract_colon_unit (path, &dirname_index))) 178 1.1 christos { 179 1.1 christos register int i, pre_suffix_length; 180 1.1 christos char *temp; 181 1.1 christos 182 1.1 christos /* Expand a leading tilde if one is present. */ 183 1.1 christos if (*temp_dirname == '~') 184 1.1 christos { 185 1.1 christos char *expanded_dirname; 186 1.1 christos 187 1.1 christos expanded_dirname = tilde_expand_word (temp_dirname); 188 1.1 christos free (temp_dirname); 189 1.1 christos temp_dirname = expanded_dirname; 190 1.1 christos } 191 1.1 christos 192 1.1 christos temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename)); 193 1.1 christos strcpy (temp, temp_dirname); 194 1.1 christos if (!IS_SLASH (temp[(strlen (temp)) - 1])) 195 1.1 christos strcat (temp, "/"); 196 1.1 christos strcat (temp, filename); 197 1.1 christos 198 1.1 christos pre_suffix_length = strlen (temp); 199 1.1 christos 200 1.1 christos free (temp_dirname); 201 1.1 christos 202 1.1 christos for (i = 0; info_suffixes[i]; i++) 203 1.1 christos { 204 1.1 christos strcpy (temp + pre_suffix_length, info_suffixes[i]); 205 1.1 christos 206 1.1 christos statable = (stat (temp, &finfo) == 0); 207 1.1 christos 208 1.1 christos /* If we have found a regular file, then use that. Else, if we 209 1.1 christos have found a directory, look in that directory for this file. */ 210 1.1 christos if (statable) 211 1.1 christos { 212 1.1 christos if (S_ISREG (finfo.st_mode)) 213 1.1 christos { 214 1.1 christos return (temp); 215 1.1 christos } 216 1.1 christos else if (S_ISDIR (finfo.st_mode)) 217 1.1 christos { 218 1.1 christos char *newpath, *filename_only, *newtemp; 219 1.1 christos 220 1.1 christos newpath = xstrdup (temp); 221 1.1 christos filename_only = filename_non_directory (filename); 222 1.1 christos newtemp = info_file_in_path (filename_only, newpath); 223 1.1 christos 224 1.1 christos free (newpath); 225 1.1 christos if (newtemp) 226 1.1 christos { 227 1.1 christos free (temp); 228 1.1 christos return (newtemp); 229 1.1 christos } 230 1.1 christos } 231 1.1 christos } 232 1.1 christos else 233 1.1 christos { 234 1.1 christos /* Add various compression suffixes to the name to see if 235 1.1 christos the file is present in compressed format. */ 236 1.1 christos register int j, pre_compress_suffix_length; 237 1.1 christos 238 1.1 christos pre_compress_suffix_length = strlen (temp); 239 1.1 christos 240 1.1 christos for (j = 0; compress_suffixes[j].suffix; j++) 241 1.1 christos { 242 1.1 christos strcpy (temp + pre_compress_suffix_length, 243 1.1 christos compress_suffixes[j].suffix); 244 1.1 christos 245 1.1 christos statable = (stat (temp, &finfo) == 0); 246 1.1 christos if (statable && (S_ISREG (finfo.st_mode))) 247 1.1 christos return (temp); 248 1.1 christos } 249 1.1 christos } 250 1.1 christos } 251 1.1 christos free (temp); 252 1.1 christos } 253 1.1 christos return ((char *)NULL); 254 1.1 christos } 255 1.1 christos 256 1.1 christos /* Assume FNAME is an absolute file name, and check whether it is 257 1.1 christos a regular file. If it is, return it as a new string; otherwise 258 1.1 christos return a NULL pointer. We do it by taking the file name apart 259 1.1 christos into its directory and basename parts, and calling info_file_in_path.*/ 260 1.1 christos static char * 261 1.1 christos info_absolute_file (char *fname) 262 1.1 christos { 263 1.1 christos char *containing_dir = xstrdup (fname); 264 1.1 christos char *base = filename_non_directory (containing_dir); 265 1.1 christos 266 1.1 christos if (base > containing_dir) 267 1.1 christos base[-1] = '\0'; 268 1.1 christos 269 1.1 christos return info_file_in_path (filename_non_directory (fname), containing_dir); 270 1.1 christos } 271 1.1 christos 272 1.1 christos 273 1.1 christos /* Given a string containing units of information separated by the 274 1.1 christos PATH_SEP character, return the next one after IDX, or NULL if there 275 1.1 christos are no more. Advance IDX to the character after the colon. */ 276 1.1 christos 277 1.1 christos char * 278 1.1 christos extract_colon_unit (char *string, int *idx) 279 1.1 christos { 280 1.1 christos unsigned int i = (unsigned int) *idx; 281 1.1 christos unsigned int start = i; 282 1.1 christos 283 1.1 christos if (!string || i >= strlen (string)) 284 1.1 christos return NULL; 285 1.1 christos 286 1.1 christos if (!string[i]) /* end of string */ 287 1.1 christos return NULL; 288 1.1 christos 289 1.1 christos /* Advance to next PATH_SEP. */ 290 1.1 christos while (string[i] && string[i] != PATH_SEP[0]) 291 1.1 christos i++; 292 1.1 christos 293 1.1 christos { 294 1.1 christos char *value = xmalloc ((i - start) + 1); 295 1.1 christos strncpy (value, &string[start], (i - start)); 296 1.1 christos value[i - start] = 0; 297 1.1 christos 298 1.1 christos i++; /* move past PATH_SEP */ 299 1.1 christos *idx = i; 300 1.1 christos return value; 301 1.1 christos } 302 1.1 christos } 303 1.1 christos 304 1.1 christos /* A structure which associates a filename with its expansion. */ 305 1.1 christos typedef struct 306 1.1 christos { 307 1.1 christos char *filename; 308 1.1 christos char *expansion; 309 1.1 christos } FILENAME_LIST; 310 1.1 christos 311 1.1 christos /* An array of remembered arguments and results. */ 312 1.1 christos static FILENAME_LIST **names_and_files = (FILENAME_LIST **)NULL; 313 1.1 christos static int names_and_files_index = 0; 314 1.1 christos static int names_and_files_slots = 0; 315 1.1 christos 316 1.1 christos /* Find the result for having already called info_find_fullpath () with 317 1.1 christos FILENAME. */ 318 1.1 christos static char * 319 1.1 christos lookup_info_filename (char *filename) 320 1.1 christos { 321 1.1 christos if (filename && names_and_files) 322 1.1 christos { 323 1.1 christos register int i; 324 1.1 christos for (i = 0; names_and_files[i]; i++) 325 1.1 christos { 326 1.1 christos if (FILENAME_CMP (names_and_files[i]->filename, filename) == 0) 327 1.1 christos return (names_and_files[i]->expansion); 328 1.1 christos } 329 1.1 christos } 330 1.1 christos return (char *)NULL;; 331 1.1 christos } 332 1.1 christos 333 1.1 christos /* Add a filename and its expansion to our list. */ 334 1.1 christos static void 335 1.1 christos remember_info_filename (char *filename, char *expansion) 336 1.1 christos { 337 1.1 christos FILENAME_LIST *new; 338 1.1 christos 339 1.1 christos if (names_and_files_index + 2 > names_and_files_slots) 340 1.1 christos { 341 1.1 christos int alloc_size; 342 1.1 christos names_and_files_slots += 10; 343 1.1 christos 344 1.1 christos alloc_size = names_and_files_slots * sizeof (FILENAME_LIST *); 345 1.1 christos 346 1.1 christos names_and_files = 347 1.1 christos (FILENAME_LIST **) xrealloc (names_and_files, alloc_size); 348 1.1 christos } 349 1.1 christos 350 1.1 christos new = (FILENAME_LIST *)xmalloc (sizeof (FILENAME_LIST)); 351 1.1 christos new->filename = xstrdup (filename); 352 1.1 christos new->expansion = expansion ? xstrdup (expansion) : (char *)NULL; 353 1.1 christos 354 1.1 christos names_and_files[names_and_files_index++] = new; 355 1.1 christos names_and_files[names_and_files_index] = (FILENAME_LIST *)NULL; 356 1.1 christos } 357 1.1 christos 358 1.1 christos static void 359 1.1 christos maybe_initialize_infopath (void) 360 1.1 christos { 361 1.1 christos if (!infopath_size) 362 1.1 christos { 363 1.1 christos infopath = (char *) 364 1.1 christos xmalloc (infopath_size = (1 + strlen (DEFAULT_INFOPATH))); 365 1.1 christos 366 1.1 christos strcpy (infopath, DEFAULT_INFOPATH); 367 1.1 christos } 368 1.1 christos } 369 1.1 christos 370 1.1 christos /* Add PATH to the list of paths found in INFOPATH. 2nd argument says 371 1.1 christos whether to put PATH at the front or end of INFOPATH. */ 372 1.1 christos void 373 1.1 christos info_add_path (char *path, int where) 374 1.1 christos { 375 1.1 christos int len; 376 1.1 christos 377 1.1 christos if (!infopath) 378 1.1 christos { 379 1.1 christos infopath = (char *)xmalloc (infopath_size = 200 + strlen (path)); 380 1.1 christos infopath[0] = '\0'; 381 1.1 christos } 382 1.1 christos 383 1.1 christos len = strlen (path) + strlen (infopath); 384 1.1 christos 385 1.1 christos if (len + 2 >= infopath_size) 386 1.1 christos infopath = (char *)xrealloc (infopath, (infopath_size += (2 * len) + 2)); 387 1.1 christos 388 1.1 christos if (!*infopath) 389 1.1 christos strcpy (infopath, path); 390 1.1 christos else if (where == INFOPATH_APPEND) 391 1.1 christos { 392 1.1 christos strcat (infopath, PATH_SEP); 393 1.1 christos strcat (infopath, path); 394 1.1 christos } 395 1.1 christos else if (where == INFOPATH_PREPEND) 396 1.1 christos { 397 1.1 christos char *temp = xstrdup (infopath); 398 1.1 christos strcpy (infopath, path); 399 1.1 christos strcat (infopath, PATH_SEP); 400 1.1 christos strcat (infopath, temp); 401 1.1 christos free (temp); 402 1.1 christos } 403 1.1 christos } 404 1.1 christos 405 1.1 christos /* Make INFOPATH have absolutely nothing in it. */ 406 1.1 christos void 407 1.1 christos zap_infopath (void) 408 1.1 christos { 409 1.1 christos if (infopath) 410 1.1 christos free (infopath); 411 1.1 christos 412 1.1 christos infopath = (char *)NULL; 413 1.1 christos infopath_size = 0; 414 1.1 christos } 415 1.1 christos 416 1.1 christos /* Given a chunk of text and its length, convert all CRLF pairs at every 417 1.1 christos end-of-line into a single Newline character. Return the length of 418 1.1 christos produced text. 419 1.1 christos 420 1.1 christos This is required because the rest of code is too entrenched in having 421 1.1 christos a single newline at each EOL; in particular, searching for various 422 1.1 christos Info headers and cookies can become extremely tricky if that assumption 423 1.1 christos breaks. 424 1.1 christos 425 1.1 christos FIXME: this could also support Mac-style text files with a single CR 426 1.1 christos at the EOL, but what about random CR characters in non-Mac files? Can 427 1.1 christos we afford converting them into newlines as well? Maybe implement some 428 1.1 christos heuristics here, like in Emacs 20. 429 1.1 christos 430 1.1 christos FIXME: is it a good idea to show the EOL type on the modeline? */ 431 1.1 christos long 432 1.1 christos convert_eols (char *text, long int textlen) 433 1.1 christos { 434 1.1 christos register char *s = text; 435 1.1 christos register char *d = text; 436 1.1 christos 437 1.1 christos while (textlen--) 438 1.1 christos { 439 1.1 christos if (*s == '\r' && textlen && s[1] == '\n') 440 1.1 christos { 441 1.1 christos s++; 442 1.1 christos textlen--; 443 1.1 christos } 444 1.1 christos *d++ = *s++; 445 1.1 christos } 446 1.1 christos 447 1.1 christos return (long)(d - text); 448 1.1 christos } 449 1.1 christos 450 1.1 christos /* Read the contents of PATHNAME, returning a buffer with the contents of 451 1.1 christos that file in it, and returning the size of that buffer in FILESIZE. 452 1.1 christos FINFO is a stat struct which has already been filled in by the caller. 453 1.1 christos If the file turns out to be compressed, set IS_COMPRESSED to non-zero. 454 1.1 christos If the file cannot be read, return a NULL pointer. */ 455 1.1 christos char * 456 1.1 christos filesys_read_info_file (char *pathname, long int *filesize, 457 1.1 christos struct stat *finfo, int *is_compressed) 458 1.1 christos { 459 1.1 christos long st_size; 460 1.1 christos 461 1.1 christos *filesize = filesys_error_number = 0; 462 1.1 christos 463 1.1 christos if (compressed_filename_p (pathname)) 464 1.1 christos { 465 1.1 christos *is_compressed = 1; 466 1.1 christos return (filesys_read_compressed (pathname, filesize)); 467 1.1 christos } 468 1.1 christos else 469 1.1 christos { 470 1.1 christos int descriptor; 471 1.1 christos char *contents; 472 1.1 christos 473 1.1 christos *is_compressed = 0; 474 1.1 christos descriptor = open (pathname, O_RDONLY | O_BINARY, 0666); 475 1.1 christos 476 1.1 christos /* If the file couldn't be opened, give up. */ 477 1.1 christos if (descriptor < 0) 478 1.1 christos { 479 1.1 christos filesys_error_number = errno; 480 1.1 christos return ((char *)NULL); 481 1.1 christos } 482 1.1 christos 483 1.1 christos /* Try to read the contents of this file. */ 484 1.1 christos st_size = (long) finfo->st_size; 485 1.1 christos contents = (char *)xmalloc (1 + st_size); 486 1.1 christos if ((read (descriptor, contents, st_size)) != st_size) 487 1.1 christos { 488 1.1 christos filesys_error_number = errno; 489 1.1 christos close (descriptor); 490 1.1 christos free (contents); 491 1.1 christos return ((char *)NULL); 492 1.1 christos } 493 1.1 christos 494 1.1 christos close (descriptor); 495 1.1 christos 496 1.1 christos /* Convert any DOS-style CRLF EOLs into Unix-style NL. 497 1.1 christos Seems like a good idea to have even on Unix, in case the Info 498 1.1 christos files are coming from some Windows system across a network. */ 499 1.1 christos *filesize = convert_eols (contents, st_size); 500 1.1 christos 501 1.1 christos /* EOL conversion can shrink the text quite a bit. We don't 502 1.1 christos want to waste storage. */ 503 1.1 christos if (*filesize < st_size) 504 1.1 christos contents = (char *)xrealloc (contents, 1 + *filesize); 505 1.1 christos contents[*filesize] = '\0'; 506 1.1 christos 507 1.1 christos return (contents); 508 1.1 christos } 509 1.1 christos } 510 1.1 christos 511 1.1 christos /* Typically, pipe buffers are 4k. */ 512 1.1 christos #define BASIC_PIPE_BUFFER (4 * 1024) 513 1.1 christos 514 1.1 christos /* We use some large multiple of that. */ 515 1.1 christos #define FILESYS_PIPE_BUFFER_SIZE (16 * BASIC_PIPE_BUFFER) 516 1.1 christos 517 1.1 christos char * 518 1.1 christos filesys_read_compressed (char *pathname, long int *filesize) 519 1.1 christos { 520 1.1 christos FILE *stream; 521 1.1 christos char *command, *decompressor; 522 1.1 christos char *contents = (char *)NULL; 523 1.1 christos 524 1.1 christos *filesize = filesys_error_number = 0; 525 1.1 christos 526 1.1 christos decompressor = filesys_decompressor_for_file (pathname); 527 1.1 christos 528 1.1 christos if (!decompressor) 529 1.1 christos return ((char *)NULL); 530 1.1 christos 531 1.1 christos command = (char *)xmalloc (15 + strlen (pathname) + strlen (decompressor)); 532 1.1 christos /* Explicit .exe suffix makes the diagnostics of `popen' 533 1.1 christos better on systems where COMMAND.COM is the stock shell. */ 534 1.1 christos sprintf (command, "%s%s < %s", 535 1.1 christos decompressor, STRIP_DOT_EXE ? ".exe" : "", pathname); 536 1.1 christos 537 1.1 christos #if !defined (BUILDING_LIBRARY) 538 1.1 christos if (info_windows_initialized_p) 539 1.1 christos { 540 1.1 christos char *temp; 541 1.1 christos 542 1.1 christos temp = (char *)xmalloc (5 + strlen (command)); 543 1.1 christos sprintf (temp, "%s...", command); 544 1.1 christos message_in_echo_area ("%s", temp, NULL); 545 1.1 christos free (temp); 546 1.1 christos } 547 1.1 christos #endif /* !BUILDING_LIBRARY */ 548 1.1 christos 549 1.1 christos stream = popen (command, FOPEN_RBIN); 550 1.1 christos free (command); 551 1.1 christos 552 1.1 christos /* Read chunks from this file until there are none left to read. */ 553 1.1 christos if (stream) 554 1.1 christos { 555 1.1 christos long offset, size; 556 1.1 christos char *chunk; 557 1.1 christos 558 1.1 christos offset = size = 0; 559 1.1 christos chunk = (char *)xmalloc (FILESYS_PIPE_BUFFER_SIZE); 560 1.1 christos 561 1.1 christos while (1) 562 1.1 christos { 563 1.1 christos int bytes_read; 564 1.1 christos 565 1.1 christos bytes_read = fread (chunk, 1, FILESYS_PIPE_BUFFER_SIZE, stream); 566 1.1 christos 567 1.1 christos if (bytes_read + offset >= size) 568 1.1 christos contents = (char *)xrealloc 569 1.1 christos (contents, size += (2 * FILESYS_PIPE_BUFFER_SIZE)); 570 1.1 christos 571 1.1 christos memcpy (contents + offset, chunk, bytes_read); 572 1.1 christos offset += bytes_read; 573 1.1 christos if (bytes_read != FILESYS_PIPE_BUFFER_SIZE) 574 1.1 christos break; 575 1.1 christos } 576 1.1 christos 577 1.1 christos free (chunk); 578 1.1 christos if (pclose (stream) == -1) 579 1.1 christos { 580 1.1 christos if (contents) 581 1.1 christos free (contents); 582 1.1 christos contents = (char *)NULL; 583 1.1 christos filesys_error_number = errno; 584 1.1 christos } 585 1.1 christos else 586 1.1 christos { 587 1.1 christos *filesize = convert_eols (contents, offset); 588 1.1 christos contents = (char *)xrealloc (contents, 1 + *filesize); 589 1.1 christos contents[*filesize] = '\0'; 590 1.1 christos } 591 1.1 christos } 592 1.1 christos else 593 1.1 christos { 594 1.1 christos filesys_error_number = errno; 595 1.1 christos } 596 1.1 christos 597 1.1 christos #if !defined (BUILDING_LIBARARY) 598 1.1 christos if (info_windows_initialized_p) 599 1.1 christos unmessage_in_echo_area (); 600 1.1 christos #endif /* !BUILDING_LIBRARY */ 601 1.1 christos return (contents); 602 1.1 christos } 603 1.1 christos 604 1.1 christos /* Return non-zero if FILENAME belongs to a compressed file. */ 605 1.1 christos int 606 1.1 christos compressed_filename_p (char *filename) 607 1.1 christos { 608 1.1 christos char *decompressor; 609 1.1 christos 610 1.1 christos /* Find the final extension of this filename, and see if it matches one 611 1.1 christos of our known ones. */ 612 1.1 christos decompressor = filesys_decompressor_for_file (filename); 613 1.1 christos 614 1.1 christos if (decompressor) 615 1.1 christos return (1); 616 1.1 christos else 617 1.1 christos return (0); 618 1.1 christos } 619 1.1 christos 620 1.1 christos /* Return the command string that would be used to decompress FILENAME. */ 621 1.1 christos char * 622 1.1 christos filesys_decompressor_for_file (char *filename) 623 1.1 christos { 624 1.1 christos register int i; 625 1.1 christos char *extension = (char *)NULL; 626 1.1 christos 627 1.1 christos /* Find the final extension of FILENAME, and see if it appears in our 628 1.1 christos list of known compression extensions. */ 629 1.1 christos for (i = strlen (filename) - 1; i > 0; i--) 630 1.1 christos if (filename[i] == '.') 631 1.1 christos { 632 1.1 christos extension = filename + i; 633 1.1 christos break; 634 1.1 christos } 635 1.1 christos 636 1.1 christos if (!extension) 637 1.1 christos return ((char *)NULL); 638 1.1 christos 639 1.1 christos for (i = 0; compress_suffixes[i].suffix; i++) 640 1.1 christos if (FILENAME_CMP (extension, compress_suffixes[i].suffix) == 0) 641 1.1 christos return (compress_suffixes[i].decompressor); 642 1.1 christos 643 1.1 christos #if defined (__MSDOS__) 644 1.1 christos /* If no other suffix matched, allow any extension which ends 645 1.1 christos with `z' to be decompressed by gunzip. Due to limited 8+3 DOS 646 1.1 christos file namespace, we can expect many such cases, and supporting 647 1.1 christos every weird suffix thus produced would be a pain. */ 648 1.1 christos if (extension[strlen (extension) - 1] == 'z' || 649 1.1 christos extension[strlen (extension) - 1] == 'Z') 650 1.1 christos return "gunzip"; 651 1.1 christos #endif 652 1.1 christos 653 1.1 christos return ((char *)NULL); 654 1.1 christos } 655 1.1 christos 656 1.1 christos /* The number of the most recent file system error. */ 657 1.1 christos int filesys_error_number = 0; 658 1.1 christos 659 1.1 christos /* A function which returns a pointer to a static buffer containing 660 1.1 christos an error message for FILENAME and ERROR_NUM. */ 661 1.1 christos static char *errmsg_buf = (char *)NULL; 662 1.1 christos static int errmsg_buf_size = 0; 663 1.1 christos 664 1.1 christos char * 665 1.1 christos filesys_error_string (char *filename, int error_num) 666 1.1 christos { 667 1.1 christos int len; 668 1.1 christos char *result; 669 1.1 christos 670 1.1 christos if (error_num == 0) 671 1.1 christos return ((char *)NULL); 672 1.1 christos 673 1.1 christos result = strerror (error_num); 674 1.1 christos 675 1.1 christos len = 4 + strlen (filename) + strlen (result); 676 1.1 christos if (len >= errmsg_buf_size) 677 1.1 christos errmsg_buf = (char *)xrealloc (errmsg_buf, (errmsg_buf_size = 2 + len)); 678 1.1 christos 679 1.1 christos sprintf (errmsg_buf, "%s: %s", filename, result); 680 1.1 christos return (errmsg_buf); 681 1.1 christos } 682 1.1 christos 683 1.1 christos 684 1.1 christos /* Check for "dir" with all the possible info and compression suffixes, 686 1.1 christos in combination. */ 687 1.1 christos 688 1.1 christos int 689 1.1 christos is_dir_name (char *filename) 690 1.1 christos { 691 1.1 christos unsigned i; 692 1.1 christos 693 1.1 christos for (i = 0; info_suffixes[i]; i++) 694 1.1 christos { 695 1.1 christos unsigned c; 696 1.1 christos char trydir[50]; 697 1.1 christos strcpy (trydir, "dir"); 698 1.1 christos strcat (trydir, info_suffixes[i]); 699 1.1 christos 700 1.1 christos if (strcasecmp (filename, trydir) == 0) 701 1.1 christos return 1; 702 1.1 christos 703 1.1 christos for (c = 0; compress_suffixes[c].suffix; c++) 704 1.1 christos { 705 1.1 christos char dir_compressed[50]; /* can be short */ 706 1.1 christos strcpy (dir_compressed, trydir); 707 1.1 christos strcat (dir_compressed, compress_suffixes[c].suffix); 708 1.1 christos if (strcasecmp (filename, dir_compressed) == 0) 709 1.1 christos return 1; 710 1.1 christos } 711 1.1 christos } 712 1.1 christos 713 1.1 christos return 0; 714 } 715