Use <wiretap/file_util.h> to include "file_util.h"; otherwise, the
[obnox/wireshark/wip.git] / epan / filesystem.c
1 /* filesystem.c
2  * Filesystem utility routines
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33
34 #include <glib.h>
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 #ifdef HAVE_SYS_STAT_H
41 #include <sys/stat.h>
42 #endif
43
44 #ifdef HAVE_WINDOWS_H
45 #include <windows.h>
46 #endif
47
48 #ifndef _WIN32
49 #include <pwd.h>
50 #endif
51
52 #include "filesystem.h"
53 #include <wiretap/file_util.h>
54
55 /*
56  * Given a pathname, return a pointer to the last pathname separator
57  * character in the pathname, or NULL if the pathname contains no
58  * separators.
59  */
60 static char *
61 find_last_pathname_separator(const char *path)
62 {
63         char *separator;
64
65 #ifdef _WIN32
66         char c;
67
68         /*
69          * We have to scan for '\' or '/'.
70          * Get to the end of the string.
71          */
72         separator = strchr(path, '\0');         /* points to ending '\0' */
73         while (separator > path) {
74                 c = *--separator;
75                 if (c == '\\' || c == '/')
76                         return separator;       /* found it */
77         }
78
79         /*
80          * OK, we didn't find any, so no directories - but there might
81          * be a drive letter....
82          */
83         return strchr(path, ':');
84 #else
85         separator = strrchr(path, '/');
86 #endif
87         return separator;
88 }
89
90 /*
91  * Given a pathname, return the last component.
92  */
93 const char *
94 get_basename(const char *path)
95 {
96         const char *filename;
97
98         g_assert(path != NULL);
99         filename = find_last_pathname_separator(path);
100         if (filename == NULL) {
101                 /*
102                  * There're no directories, drive letters, etc. in the
103                  * name; the pathname *is* the file name.
104                  */
105                 filename = path;
106         } else {
107                 /*
108                  * Skip past the pathname or drive letter separator.
109                  */
110                 filename++;
111         }
112         return filename;
113 }
114
115 /*
116  * Given a pathname, return a string containing everything but the
117  * last component.  NOTE: this overwrites the pathname handed into
118  * it....
119  */
120 char *
121 get_dirname(char *path)
122 {
123         char *separator;
124
125         g_assert(path != NULL);
126         separator = find_last_pathname_separator(path);
127         if (separator == NULL) {
128                 /*
129                  * There're no directories, drive letters, etc. in the
130                  * name; there is no directory path to return.
131                  */
132                 return NULL;
133         }
134
135         /*
136          * Get rid of the last pathname separator and the final file
137          * name following it.
138          */
139         *separator = '\0';
140
141         /*
142          * "path" now contains the pathname of the directory containing
143          * the file/directory to which it referred.
144          */
145         return path;
146 }
147
148 /*
149  * Given a pathname, return:
150  *
151  *      the errno, if an attempt to "stat()" the file fails;
152  *
153  *      EISDIR, if the attempt succeeded and the file turned out
154  *      to be a directory;
155  *
156  *      0, if the attempt succeeded and the file turned out not
157  *      to be a directory.
158  */
159
160 /*
161  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
162  * define them either.)
163  *
164  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
165  */
166 #ifndef S_ISREG
167 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
168 #endif
169 #ifndef S_IFIFO
170 #define S_IFIFO _S_IFIFO
171 #endif
172 #ifndef S_ISFIFO
173 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
174 #endif
175 #ifndef S_ISDIR
176 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
177 #endif
178
179 int
180 test_for_directory(const char *path)
181 {
182         struct stat statb;
183
184         if (eth_stat(path, &statb) < 0)
185                 return errno;
186
187         if (S_ISDIR(statb.st_mode))
188                 return EISDIR;
189         else
190                 return 0;
191 }
192
193 int
194 test_for_fifo(const char *path)
195 {
196         struct stat statb;
197
198         if (eth_stat(path, &statb) < 0)
199                 return errno;
200
201         if (S_ISFIFO(statb.st_mode))
202                 return ESPIPE;
203         else
204                 return 0;
205 }
206
207 /*
208  * Get the directory in which Ethereal's global configuration and data
209  * files are stored.
210  *
211  * XXX - if we ever make libethereal a real library, used by multiple
212  * applications (more than just Tethereal and versions of Ethereal with
213  * various UIs), should the configuration files belong to the library
214  * (and be shared by all those applications) or to the applications?
215  *
216  * If they belong to the library, that could be done on UNIX by the
217  * configure script, but it's trickier on Windows, as you can't just
218  * use the pathname of the executable.
219  *
220  * If they belong to the application, that could be done on Windows
221  * by using the pathname of the executable, but we'd have to have it
222  * passed in as an argument, in some call, on UNIX.
223  *
224  * Note that some of those configuration files might be used by code in
225  * libethereal, some of them might be used by dissectors (would they
226  * belong to libethereal, the application, or a separate library?),
227  * and some of them might be used by other code (the Ethereal preferences
228  * file includes resolver preferences that control the behavior of code
229  * in libethereal, dissector preferences, and UI preferences, for
230  * example).
231  */
232 const char *
233 get_datafile_dir(void)
234 {
235 #ifdef _WIN32
236         char prog_pathname[_MAX_PATH+2];
237         char *dir_end;
238         size_t datafile_dir_len;
239         static char *datafile_dir;
240
241         /*
242          * Have we already gotten the pathname?
243          * If so, just return it.
244          */
245         if (datafile_dir != NULL)
246                 return datafile_dir;
247
248         /*
249          * No, we haven't.
250          * Start out by assuming it's the default installation directory.
251          */
252         datafile_dir = "C:\\Program Files\\Ethereal\\";
253
254         /*
255          * Now we attempt to get the full pathname of the currently running
256          * program, under the assumption that we're running an installed
257          * version of the program.  If we fail, we don't change "datafile_dir",
258          * and thus end up using the default.
259          *
260          * XXX - does NSIS put the installation directory into
261          * "\HKEY_LOCAL_MACHINE\SOFTWARE\Ethereal\InstallDir"?
262          * If so, perhaps we should read that from the registry,
263          * instead.
264          */
265         if (GetModuleFileName(NULL, prog_pathname, sizeof prog_pathname) != 0) {
266                 /*
267                  * If the program is an installed version, the full pathname
268                  * includes the pathname of the directory in which it was
269                  * installed; get that directory's pathname, and construct
270                  * from it the pathname of the directory in which the
271                  * plugins were installed.
272                  *
273                  * First, find the last "\\" in the directory, as that
274                  * marks the end of the directory pathname.
275                  *
276                  * XXX - Can the pathname be something such as
277                  * "C:ethereal.exe"?  Or is it always a full pathname
278                  * beginning with "\\" after the drive letter?
279                  */
280                 dir_end = strrchr(prog_pathname, '\\');
281                 if (dir_end != NULL) {
282                         /*
283                          * Found it - now figure out how long the datafile
284                          * directory pathname will be.
285                          */
286                         datafile_dir_len = (dir_end - prog_pathname);
287
288                         /*
289                          * Allocate a buffer for the plugin directory
290                          * pathname, and construct it.
291                          */
292                         datafile_dir = g_malloc(datafile_dir_len + 1);
293                         strncpy(datafile_dir, prog_pathname, datafile_dir_len);
294                         datafile_dir[datafile_dir_len] = '\0';
295                 }
296         }
297         return datafile_dir;
298 #else
299         /*
300          * Just use DATAFILE_DIR, as that's what the configure script
301          * set it to be.
302          */
303         return DATAFILE_DIR;
304 #endif
305 }
306
307 /*
308  * Get the directory in which files that, at least on UNIX, are
309  * system files (such as "/etc/ethers") are stored; on Windows,
310  * there's no "/etc" directory, so we get them from the Ethereal
311  * global configuration and data file directory.
312  */
313 const char *
314 get_systemfile_dir(void)
315 {
316 #ifdef _WIN32
317         return get_datafile_dir();
318 #else
319         return "/etc";
320 #endif
321 }
322
323 /*
324  * Name of directory, under the user's home directory, in which
325  * personal configuration files are stored.
326  */
327 #ifdef _WIN32
328 #define PF_DIR "Ethereal"
329 #else
330 /*
331  * XXX - should this be ".libepan"? For backwards-compatibility, I'll keep
332  * it ".ethereal" for now.
333  */
334 #define PF_DIR ".ethereal"
335 #endif
336
337 /*
338  * Get the directory in which personal configuration files reside;
339  * in UNIX-compatible systems, it's ".ethereal", under the user's home
340  * directory, and on Windows systems, it's "Ethereal", under %APPDATA%
341  * or, if %APPDATA% isn't set, it's "%USERPROFILE%\Application Data"
342  * (which is what %APPDATA% normally is on Windows 2000).
343  */
344 static const char *
345 get_persconffile_dir(void)
346 {
347 #ifdef _WIN32
348         char *appdatadir;
349         char *userprofiledir;
350 #else
351         const char *homedir;
352         struct passwd *pwd;
353 #endif
354         static char *pf_dir = NULL;
355
356         /* Return the cached value, if available */
357         if (pf_dir != NULL)
358                 return pf_dir;
359
360 #ifdef _WIN32
361         /*
362          * Use %APPDATA% or %USERPROFILE%, so that configuration files are
363          * stored in the user profile, rather than in the home directory.
364          * The Windows convention is to store configuration information
365          * in the user profile, and doing so means you can use
366          * Ethereal even if the home directory is an inaccessible
367          * network drive.
368          */
369         appdatadir = getenv("APPDATA");
370         if (appdatadir != NULL) {
371                 /*
372                  * Concatenate %APPDATA% with "\Ethereal".
373                  */
374                 pf_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", 
375                         appdatadir, PF_DIR);
376         } else {
377                 /*
378                  * OK, %APPDATA% wasn't set, so use
379                  * %USERPROFILE%\Application Data.
380                  */
381                 userprofiledir = getenv("USERPROFILE");
382                 if (userprofiledir != NULL) {
383                         pf_dir = g_strdup_printf(
384                             "%s" G_DIR_SEPARATOR_S "Application Data" G_DIR_SEPARATOR_S "%s",
385                             userprofiledir, PF_DIR);
386                 } else {
387                         /*
388                          * Give up and use "C:".
389                          */
390                         pf_dir = g_strdup_printf("C:" G_DIR_SEPARATOR_S "%s", PF_DIR);
391                 }
392         }
393 #else
394         /*
395          * If $HOME is set, use that.
396          */
397         homedir = getenv("HOME");
398         if (homedir == NULL) {
399                 /*
400                  * Get their home directory from the password file.
401                  * If we can't even find a password file entry for them,
402                  * use "/tmp".
403                  */
404                 pwd = getpwuid(getuid());
405                 if (pwd != NULL) {
406                         /*
407                          * This is cached, so we don't need to worry
408                          * about allocating multiple ones of them.
409                          */
410                         homedir = g_strdup(pwd->pw_dir);
411                 } else
412                         homedir = "/tmp";
413         }
414         pf_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", homedir, PF_DIR);
415 #endif
416
417         return pf_dir;
418 }
419
420 /*
421  * Create the directory that holds personal configuration files, if
422  * necessary.  If we attempted to create it, and failed, return -1 and
423  * set "*pf_dir_path_return" to the pathname of the directory we failed
424  * to create (it's g_mallocated, so our caller should free it); otherwise,
425  * return 0.
426  */
427 int
428 create_persconffile_dir(char **pf_dir_path_return)
429 {
430         const char *pf_dir_path;
431 #ifdef _WIN32
432         char *pf_dir_path_copy, *pf_dir_parent_path;
433         size_t pf_dir_parent_path_len;
434 #endif
435         struct stat s_buf;
436         int ret;
437
438         pf_dir_path = get_persconffile_dir();
439         if (eth_stat(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
440 #ifdef _WIN32
441                 /*
442                  * Does the parent directory of that directory
443                  * exist?  %APPDATA% may not exist even though
444                  * %USERPROFILE% does.
445                  *
446                  * We check for the existence of the directory
447                  * by first checking whether the parent directory
448                  * is just a drive letter and, if it's not, by
449                  * doing a "stat()" on it.  If it's a drive letter,
450                  * or if the "stat()" succeeds, we assume it exists.
451                  */
452                 pf_dir_path_copy = g_strdup(pf_dir_path);
453                 pf_dir_parent_path = get_dirname(pf_dir_path_copy);
454                 pf_dir_parent_path_len = strlen(pf_dir_parent_path);
455                 if (pf_dir_parent_path_len > 0
456                     && pf_dir_parent_path[pf_dir_parent_path_len - 1] != ':'
457                     && eth_stat(pf_dir_parent_path, &s_buf) != 0) {
458                         /*
459                          * No, it doesn't exist - make it first.
460                          */
461                         ret = eth_mkdir(pf_dir_parent_path, 0755);
462                         if (ret == -1) {
463                                 *pf_dir_path_return = pf_dir_parent_path;
464                                 return -1;
465                         }
466                 }
467                 g_free(pf_dir_path_copy);
468                 ret = eth_mkdir(pf_dir_path, 0755);
469 #else
470                 ret = eth_mkdir(pf_dir_path, 0755);
471 #endif
472         } else {
473                 /*
474                  * Something with that pathname exists; if it's not
475                  * a directory, we'll get an error if we try to put
476                  * something in it, so we don't fail here, we wait
477                  * for that attempt fo fail.
478                  */
479                 ret = 0;
480         }
481         if (ret == -1)
482                 *pf_dir_path_return = g_strdup(pf_dir_path);
483         return ret;
484 }
485
486 #ifdef _WIN32
487 /*
488  * Returns the user's home directory on Win32.
489  */
490 static const char *
491 get_home_dir(void)
492 {
493         static const char *home = NULL;
494         char *homedrive, *homepath;
495         char *homestring;
496         char *lastsep;
497
498         /* Return the cached value, if available */
499         if (home)
500                 return home;
501
502         /*
503          * XXX - should we use USERPROFILE anywhere in this process?
504          * Is there a chance that it might be set but one or more of
505          * HOMEDRIVE or HOMEPATH isn't set?
506          */
507         homedrive = getenv("HOMEDRIVE");
508         if (homedrive != NULL) {
509                 homepath = getenv("HOMEPATH");
510                 if (homepath != NULL) {
511                         /*
512                          * This is cached, so we don't need to worry about
513                          * allocating multiple ones of them.
514                          */
515                         homestring =
516                             g_malloc(strlen(homedrive) + strlen(homepath) + 1);
517                         strcpy(homestring, homedrive);
518                         strcat(homestring, homepath);
519
520                         /*
521                          * Trim off any trailing slash or backslash.
522                          */
523                         lastsep = find_last_pathname_separator(homestring);
524                         if (lastsep != NULL && *(lastsep + 1) == '\0') {
525                                 /*
526                                  * Last separator is the last character
527                                  * in the string.  Nuke it.
528                                  */
529                                 *lastsep = '\0';
530                         }
531                         home = homestring;
532                 } else
533                         home = homedrive;
534         } else {
535                 /*
536                  * Give up and use C:.
537                  */
538                 home = "C:";
539         }
540
541         return home;
542 }
543 #endif
544
545 /*
546  * Construct the path name of a personal configuration file, given the
547  * file name.
548  *
549  * On Win32, if "for_writing" is FALSE, we check whether the file exists
550  * and, if not, construct a path name relative to the ".ethereal"
551  * subdirectory of the user's home directory, and check whether that
552  * exists; if it does, we return that, so that configuration files
553  * from earlier versions can be read.
554  */
555 char *
556 get_persconffile_path(const char *filename, gboolean for_writing
557 #ifndef _WIN32
558         _U_
559 #endif
560 )
561 {
562         char *path;
563 #ifdef _WIN32
564         struct stat s_buf;
565         char *old_path;
566 #endif
567
568         path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", get_persconffile_dir(),
569             filename);
570 #ifdef _WIN32
571         if (!for_writing) {
572                 if (eth_stat(path, &s_buf) != 0 && errno == ENOENT) {
573                         /*
574                          * OK, it's not in the personal configuration file
575                          * directory; is it in the ".ethereal" subdirectory
576                          * of their home directory?
577                          */
578                         old_path = g_strdup_printf(
579                             "%s" G_DIR_SEPARATOR_S ".ethereal" G_DIR_SEPARATOR_S "%s",
580                             get_home_dir(), filename);
581                         if (eth_stat(old_path, &s_buf) == 0) {
582                                 /*
583                                  * OK, it exists; return it instead.
584                                  */
585                                 g_free(path);
586                                 path = old_path;
587                         }
588                 }
589         }
590 #endif
591
592         return path;
593 }
594
595 /*
596  * Construct the path name of a global configuration file, given the
597  * file name.
598  */
599 char *
600 get_datafile_path(const char *filename)
601 {
602
603         return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", get_datafile_dir(),
604             filename);
605 }
606
607 /* Delete a file */
608 gboolean
609 deletefile(const char *path)
610 {
611         return eth_unlink(path) == 0;
612 }
613
614 /*
615  * Construct and return the path name of a file in the
616  * appropriate temporary file directory.
617  */
618 char *get_tempfile_path(const char *filename)
619 {
620
621         return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", g_get_tmp_dir(), filename);
622 }
623
624 /*
625  * Return an error message for UNIX-style errno indications on open or
626  * create operations.
627  */
628 const char *
629 file_open_error_message(int err, gboolean for_writing)
630 {
631         const char *errmsg;
632         static char errmsg_errno[1024+1];
633
634         switch (err) {
635
636         case ENOENT:
637                 if (for_writing)
638                         errmsg = "The path to the file \"%s\" doesn't exist.";
639                 else
640                         errmsg = "The file \"%s\" doesn't exist.";
641                 break;
642
643         case EACCES:
644                 if (for_writing)
645                         errmsg = "You don't have permission to create or write to the file \"%s\".";
646                 else
647                         errmsg = "You don't have permission to read the file \"%s\".";
648                 break;
649
650         case EISDIR:
651                 errmsg = "\"%s\" is a directory (folder), not a file.";
652                 break;
653
654         case ENOSPC:
655                 errmsg = "The file \"%s\" could not be created because there is no space left on the file system.";
656                 break;
657
658 #ifdef EDQUOT
659         case EDQUOT:
660                 errmsg = "The file \"%s\" could not be created because you are too close to, or over, your disk quota.";
661                 break;
662 #endif
663
664         default:
665                 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
666                                 "The file \"%%s\" could not be %s: %s.",
667                                 for_writing ? "created" : "opened",
668                                 strerror(err));
669                 errmsg = errmsg_errno;
670                 break;
671         }
672         return errmsg;
673 }
674
675 /*
676  * Return an error message for UNIX-style errno indications on write
677  * operations.
678  */
679 const char *
680 file_write_error_message(int err)
681 {
682         const char *errmsg;
683         static char errmsg_errno[1024+1];
684
685         switch (err) {
686
687         case ENOSPC:
688                 errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
689                 break;
690
691 #ifdef EDQUOT
692         case EDQUOT:
693                 errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
694                 break;
695 #endif
696
697         default:
698                 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
699                     "An error occurred while writing to the file \"%%s\": %s.",
700                     strerror(err));
701                 errmsg = errmsg_errno;
702                 break;
703         }
704         return errmsg;
705 }
706
707
708 gboolean
709 file_exists(const char *fname)
710 {
711   struct stat   file_stat;
712
713
714   /*
715    * This is a bit tricky on win32. The st_ino field is documented as:
716    * "The inode, and therefore st_ino, has no meaning in the FAT, ..."
717    * but it *is* set to zero if stat() returns without an error,
718    * so this is working, but maybe not quite the way expected. ULFL
719    */
720    file_stat.st_ino = 1;   /* this will make things work if an error occured */
721    eth_stat(fname, &file_stat);
722    if (file_stat.st_ino == 0) {
723        return TRUE;
724    } else {
725        return FALSE;
726    }
727
728 }
729
730
731 gboolean
732 files_identical(const char *fname1, const char *fname2)
733 {
734     /* Two different implementations, because:
735      * - _fullpath is not available on unix 
736      * - the stat inode will not work as expected on Win32, so two different implementations.
737      *
738      * XXX - will _fullpath work with UNC?
739      */
740 #ifdef _WIN32
741     char full1[MAX_PATH], full2[MAX_PATH];
742
743
744     if( _fullpath( full1, fname1, MAX_PATH ) == NULL ) {
745         return FALSE;
746     }
747
748     if( _fullpath( full2, fname2, MAX_PATH ) == NULL ) {
749         return FALSE;
750     }
751     
752     if(strcmp(full1, full2) == 0) {
753         return TRUE;
754     } else {
755         return FALSE;
756     }
757 #else
758   struct stat   infile, outfile;
759
760   /*
761    * Check that the from file is not the same as to file
762    * We do it here so we catch all cases ...
763    * Unfortunately, the file requester gives us an absolute file
764    * name and the read file name may be relative (if supplied on
765    * the command line). From Joerg Mayer.
766    *
767    * This is a bit tricky on win32. The st_ino field is documented as:
768    * "The inode, and therefore st_ino, has no meaning in the FAT, ..."
769    * but it *is* set to zero if stat() returns without an error,
770    * so this is not working, as it only checks if both files existing. ULFL
771    */
772    infile.st_ino = 1;   /* These prevent us from getting equality         */
773    outfile.st_ino = 2;  /* If one or other of the files is not accessible */
774    eth_stat(fname1, &infile);
775    eth_stat(fname2, &outfile);
776    if (infile.st_ino == outfile.st_ino) {
777        return TRUE;
778    } else {
779        return FALSE;
780    }
781
782 #endif
783 }
784