Check in the OS X packaging patch from bug 2341, since I've had
[obnox/wireshark/wip.git] / epan / filesystem.c
1 /* filesystem.c
2  * Filesystem utility routines
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
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 #ifdef HAVE_DIRENT_H
30 #include <dirent.h>
31 #endif
32
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38
39 #include <glib.h>
40
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44
45 #ifdef HAVE_SYS_STAT_H
46 #include <sys/stat.h>
47 #endif
48
49 #ifdef _WIN32
50 #include <windows.h>
51 #include <tchar.h>
52 #include <shlobj.h>
53 #include "epan/unicode-utils.h"
54 #else
55 #include <pwd.h>
56 #endif
57
58 #include "filesystem.h"
59 #include "privileges.h"
60 #include <wiretap/file_util.h>
61
62 #define PROFILES_DIR    "profiles"
63 #define U3_MY_CAPTURES  "\\My Captures"
64
65 char *persconffile_dir = NULL;
66 char *persdatafile_dir = NULL;
67 char *persconfprofile = NULL;
68
69 /*
70  * Given a pathname, return a pointer to the last pathname separator
71  * character in the pathname, or NULL if the pathname contains no
72  * separators.
73  */
74 static char *
75 find_last_pathname_separator(const char *path)
76 {
77         char *separator;
78
79 #ifdef _WIN32
80         char c;
81
82         /*
83          * We have to scan for '\' or '/'.
84          * Get to the end of the string.
85          */
86         separator = strchr(path, '\0');         /* points to ending '\0' */
87         while (separator > path) {
88                 c = *--separator;
89                 if (c == '\\' || c == '/')
90                         return separator;       /* found it */
91         }
92
93         /*
94          * OK, we didn't find any, so no directories - but there might
95          * be a drive letter....
96          */
97         return strchr(path, ':');
98 #else
99         separator = strrchr(path, '/');
100 #endif
101         return separator;
102 }
103
104 /*
105  * Given a pathname, return the last component.
106  */
107 const char *
108 get_basename(const char *path)
109 {
110         const char *filename;
111
112         g_assert(path != NULL);
113         filename = find_last_pathname_separator(path);
114         if (filename == NULL) {
115                 /*
116                  * There're no directories, drive letters, etc. in the
117                  * name; the pathname *is* the file name.
118                  */
119                 filename = path;
120         } else {
121                 /*
122                  * Skip past the pathname or drive letter separator.
123                  */
124                 filename++;
125         }
126         return filename;
127 }
128
129 /*
130  * Given a pathname, return a string containing everything but the
131  * last component.  NOTE: this overwrites the pathname handed into
132  * it....
133  */
134 char *
135 get_dirname(char *path)
136 {
137         char *separator;
138
139         g_assert(path != NULL);
140         separator = find_last_pathname_separator(path);
141         if (separator == NULL) {
142                 /*
143                  * There're no directories, drive letters, etc. in the
144                  * name; there is no directory path to return.
145                  */
146                 return NULL;
147         }
148
149         /*
150          * Get rid of the last pathname separator and the final file
151          * name following it.
152          */
153         *separator = '\0';
154
155         /*
156          * "path" now contains the pathname of the directory containing
157          * the file/directory to which it referred.
158          */
159         return path;
160 }
161
162 /*
163  * Given a pathname, return:
164  *
165  *      the errno, if an attempt to "stat()" the file fails;
166  *
167  *      EISDIR, if the attempt succeeded and the file turned out
168  *      to be a directory;
169  *
170  *      0, if the attempt succeeded and the file turned out not
171  *      to be a directory.
172  */
173
174 /*
175  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
176  * define them either.)
177  *
178  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
179  */
180 #ifndef S_ISREG
181 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
182 #endif
183 #ifndef S_IFIFO
184 #define S_IFIFO _S_IFIFO
185 #endif
186 #ifndef S_ISFIFO
187 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
188 #endif
189 #ifndef S_ISDIR
190 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
191 #endif
192
193 int
194 test_for_directory(const char *path)
195 {
196         struct stat statb;
197
198         if (eth_stat(path, &statb) < 0)
199                 return errno;
200
201         if (S_ISDIR(statb.st_mode))
202                 return EISDIR;
203         else
204                 return 0;
205 }
206
207 int
208 test_for_fifo(const char *path)
209 {
210         struct stat statb;
211
212         if (eth_stat(path, &statb) < 0)
213                 return errno;
214
215         if (S_ISFIFO(statb.st_mode))
216                 return ESPIPE;
217         else
218                 return 0;
219 }
220
221 /*
222  * Directory from which the executable came.
223  */
224 static char *progfile_dir;
225
226 /*
227  * TRUE if we're running from the build directory and we aren't running
228  * with special privileges.
229  */
230 static gboolean running_in_build_directory_flag = FALSE;
231
232 /*
233  * Get the pathname of the directory from which the executable came,
234  * and save it for future use.  Returns NULL on success, and a
235  * g_mallocated string containing an error on failure.
236  */
237 char *
238 init_progfile_dir(const char *arg0
239 #ifdef _WIN32
240         _U_
241 #endif
242 )
243 {
244         char *dir_end;
245         char *path;
246 #ifdef _WIN32
247         TCHAR prog_pathname_w[_MAX_PATH+2];
248         size_t progfile_dir_len;
249         char *prog_pathname;
250         DWORD error;
251         TCHAR *msg_w;
252         guchar *msg;
253         size_t msglen;
254
255         /*
256          * Attempt to get the full pathname of the currently running
257          * program.
258          */
259         if (GetModuleFileName(NULL, prog_pathname_w, sizeof prog_pathname_w) != 0) {
260                 /*
261                  * XXX - Should we use g_utf16_to_utf8(), as in
262                  * getenv_utf8()?
263                  */
264                 prog_pathname = utf_16to8(prog_pathname_w);
265                 /*
266                  * We got it; strip off the last component, which would be
267                  * the file name of the executable, giving us the pathname
268                  * of the directory where the executable resies
269                  *
270                  * First, find the last "\" in the directory, as that
271                  * marks the end of the directory pathname.
272                  *
273                  * XXX - Can the pathname be something such as
274                  * "C:wireshark.exe"?  Or is it always a full pathname
275                  * beginning with "\" after the drive letter?
276                  */
277                 dir_end = strrchr(prog_pathname, '\\');
278                 if (dir_end != NULL) {
279                         /*
280                          * Found it - now figure out how long the program
281                          * directory pathname will be.
282                          */
283                         progfile_dir_len = (dir_end - prog_pathname);
284
285                         /*
286                          * Allocate a buffer for the program directory
287                          * pathname, and construct it.
288                          */
289                         path = g_malloc(progfile_dir_len + 1);
290                         strncpy(path, prog_pathname, progfile_dir_len);
291                         path[progfile_dir_len] = '\0';
292                         progfile_dir = path;
293
294                         return NULL;    /* we succeeded */
295                 } else {
296                         /*
297                          * OK, no \ - what do we do now?
298                          */
299                         return g_strdup_printf("No \\ in executable pathname \"%s\"",
300                             prog_pathname);
301                 }
302         } else {
303                 /*
304                  * Oh, well.  Return an indication of the error.
305                  */
306                 error = GetLastError();
307                 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
308                     NULL, error, 0, (LPTSTR) &msg_w, 0, NULL) == 0) {
309                         /*
310                          * Gak.  We can't format the message.
311                          */
312                         return g_strdup_printf("GetModuleFileName failed: %u (FormatMessage failed: %u)",
313                             error, GetLastError());
314                 }
315                 msg = utf_16to8(msg_w);
316                 LocalFree(msg_w);
317                 /*
318                  * "FormatMessage()" "helpfully" sticks CR/LF at the
319                  * end of the message.  Get rid of it.
320                  */
321                 msglen = strlen(msg);
322                 if (msglen >= 2) {
323                         msg[msglen - 1] = '\0';
324                         msg[msglen - 2] = '\0';
325                 }
326                 return g_strdup_printf("GetModuleFileName failed: %s (%u)",
327                     msg, error);
328         }
329 #else
330         char *prog_pathname;
331         char *curdir;
332         long path_max;
333         char *pathstr;
334         char *path_start, *path_end;
335         size_t path_component_len;
336         char *retstr;
337
338         /*
339          * Check whether WIRESHARK_RUN_FROM_BUILD_DIRECTORY is set in the
340          * environment; if so, set running_in_build_directory_flag if we
341          * weren't started with special privileges.  (If we were started
342          * with special privileges, it's not safe to allow the user to point
343          * us to some other directory; running_in_build_directory_flag, when
344          * set, causes us to look for plugins and the like in the build
345          * directory.)
346          */
347         if (getenv("WIRESHARK_RUN_FROM_BUILD_DIRECTORY") != NULL
348             && !started_with_special_privs())
349                 running_in_build_directory_flag = TRUE;
350
351         /*
352          * Try to figure out the directory in which the currently running
353          * program resides, given the argv[0] it was started with.  That
354          * might be the absolute path of the program, or a path relative
355          * to the current directory of the process that started it, or
356          * just a name for the program if it was started from the command
357          * line and was searched for in $PATH.  It's not guaranteed to be
358          * any of those, however, so there are no guarantees....
359          */
360         if (arg0[0] == '/') {
361                 /*
362                  * It's an absolute path.
363                  */
364                 prog_pathname = g_strdup(arg0);
365         } else if (strchr(arg0, '/') != NULL) {
366                 /*
367                  * It's a relative path, with a directory in it.
368                  * Get the current directory, and combine it
369                  * with that directory.
370                  */
371                 path_max = pathconf(".", _PC_PATH_MAX);
372                 if (path_max == -1) {
373                         /*
374                          * We have no idea how big a buffer to
375                          * allocate for the current directory.
376                          */
377                         return g_strdup_printf("pathconf failed: %s\n",
378                             strerror(errno));
379                 }
380                 curdir = g_malloc(path_max);
381                 if (getcwd(curdir, path_max) == NULL) {
382                         /*
383                          * It failed - give up, and just stick
384                          * with DATAFILE_DIR.
385                          */
386                         g_free(curdir);
387                         return g_strdup_printf("getcwd failed: %s\n",
388                             strerror(errno));
389                 }
390                 path = g_strdup_printf("%s/%s", curdir, arg0);
391                 g_free(curdir);
392                 prog_pathname = path;
393         } else {
394                 /*
395                  * It's just a file name.
396                  * Search the path for a file with that name
397                  * that's executable.
398                  */
399                 prog_pathname = NULL;   /* haven't found it yet */
400                 pathstr = getenv("PATH");
401                 path_start = pathstr;
402                 if (path_start != NULL) {
403                         while (*path_start != '\0') {
404                                 path_end = strchr(path_start, ':');
405                                 if (path_end == NULL)
406                                         path_end = path_start + strlen(path_start);
407                                 path_component_len = path_end - path_start;
408                                 path = g_malloc(path_component_len + 1
409                                     + strlen(arg0) + 1);
410                                 memcpy(path, path_start, path_component_len);
411                                 path[path_component_len] = '\0';
412                                 strncat(path, "/", 2);
413                                 strncat(path, arg0, strlen(arg0) + 1);
414                                 if (access(path, X_OK) == 0) {
415                                         /*
416                                          * Found it!
417                                          */
418                                         prog_pathname = path;
419                                         break;
420                                 }
421
422                                 /*
423                                  * That's not it.  If there are more
424                                  * path components to test, try them.
425                                  */
426                                 if (*path_end == '\0') {
427                                         /*
428                                          * There's nothing more to try.
429                                          */
430                                         break;
431                                 }
432                                 if (*path_end == ':')
433                                         path_end++;
434                                 path_start = path_end;
435                                 g_free(path);
436                         }
437                         if (prog_pathname == NULL) {
438                                 /*
439                                  * Program not found in path.
440                                  */
441                                 return g_strdup_printf("\"%s\" not found in \"%s\"",
442                                     arg0, pathstr);
443                         }
444                 } else {
445                         /*
446                          * PATH isn't set.
447                          * XXX - should we pick a default?
448                          */
449                         return g_strdup("PATH isn't set");
450                 }
451         }
452
453         /*
454          * OK, we have what we think is the pathname
455          * of the program.
456          *
457          * First, find the last "/" in the directory,
458          * as that marks the end of the directory pathname.
459          */
460         dir_end = strrchr(prog_pathname, '/');
461         if (dir_end != NULL) {
462                 /*
463                  * Found it.  Strip off the last component,
464                  * as that's the path of the program.
465                  */
466                 *dir_end = '\0';
467
468                 /*
469                  * Is there a "/.libs" at the end?
470                  */
471                 dir_end = strrchr(prog_pathname, '/');
472                 if (dir_end != NULL) {
473                         if (strcmp(dir_end, "/.libs") == 0) {
474                                 /*
475                                  * Yup, it's ".libs".
476                                  * Strip that off; it's an
477                                  * artifact of libtool.
478                                  */
479                                 *dir_end = '\0';
480
481                                 /*
482                                  * This presumably means we're run from
483                                  * the libtool wrapper, which probably
484                                  * means we're being run from the build
485                                  * directory.  If we weren't started
486                                  * with special privileges, set
487                                  * running_in_build_directory_flag.
488                                  *
489                                  * XXX - should we check whether what
490                                  * follows ".libs/" begins with "lt-"?
491                                  */
492                                 if (!started_with_special_privs())
493                                         running_in_build_directory_flag = TRUE;
494                         }
495                 }
496
497                 /*
498                  * OK, we have the path we want.
499                  */
500                 progfile_dir = prog_pathname;
501                 return NULL;
502         } else {
503                 /*
504                  * This "shouldn't happen"; we apparently
505                  * have no "/" in the pathname.
506                  * Just free up prog_pathname.
507                  */
508                 retstr = g_strdup_printf("No / found in \"%s\"", prog_pathname);
509                 g_free(prog_pathname);
510                 return retstr;
511         }
512 #endif
513 }
514
515 /*
516  * Get the directory in which the program resides.
517  */
518 const char *
519 get_progfile_dir(void)
520 {
521         return progfile_dir;
522 }
523
524 /*
525  * Get the directory in which the global configuration and data files are
526  * stored.
527  *
528  * On Windows, we use the directory in which the executable for this
529  * process resides.
530  *
531  * On UN*X, we use the DATAFILE_DIR value supplied by the configure
532  * script, unless we think we're being run from the build directory,
533  * in which case we use the directory in which the executable for this
534  * process resides.
535  *
536  * XXX - if we ever make libwireshark a real library, used by multiple
537  * applications (more than just TShark and versions of Wireshark with
538  * various UIs), should the configuration files belong to the library
539  * (and be shared by all those applications) or to the applications?
540  *
541  * If they belong to the library, that could be done on UNIX by the
542  * configure script, but it's trickier on Windows, as you can't just
543  * use the pathname of the executable.
544  *
545  * If they belong to the application, that could be done on Windows
546  * by using the pathname of the executable, but we'd have to have it
547  * passed in as an argument, in some call, on UNIX.
548  *
549  * Note that some of those configuration files might be used by code in
550  * libwireshark, some of them might be used by dissectors (would they
551  * belong to libwireshark, the application, or a separate library?),
552  * and some of them might be used by other code (the Wireshark preferences
553  * file includes resolver preferences that control the behavior of code
554  * in libwireshark, dissector preferences, and UI preferences, for
555  * example).
556  */
557 const char *
558 get_datafile_dir(void)
559 {
560 #ifdef _WIN32
561         char *u3deviceexecpath;
562 #endif
563         static char *datafile_dir = NULL;
564
565         if (datafile_dir != NULL)
566                 return datafile_dir;
567
568 #ifdef _WIN32
569         /*
570          * See if we are running in a U3 environment.
571          */
572         u3deviceexecpath = getenv_utf8("U3_DEVICE_EXEC_PATH");
573
574         if (u3deviceexecpath != NULL) {
575                 /*
576                  * We are; use the U3 device executable path.
577                  */
578                 datafile_dir = u3deviceexecpath;
579         } else {
580                 /*
581                  * Do we have the pathname of the program?  If so, assume we're
582                  * running an installed version of the program.  If we fail,
583                  * we don't change "datafile_dir", and thus end up using the
584                  * default.
585                  *
586                  * XXX - does NSIS put the installation directory into
587                  * "\HKEY_LOCAL_MACHINE\SOFTWARE\Wireshark\InstallDir"?
588                  * If so, perhaps we should read that from the registry,
589                  * instead.
590                  */
591                 if (progfile_dir != NULL) {
592                         /*
593                          * Yes, we do; use that.
594                          */
595                         datafile_dir = progfile_dir;
596                 } else {
597                         /*
598                          * No, we don't.
599                          * Fall back on the default installation directory.
600                          */
601                         datafile_dir = "C:\\Program Files\\Wireshark\\";
602                 }
603         }
604 #else
605         if (running_in_build_directory_flag && progfile_dir != NULL) {
606                 /*
607                  * We're (probably) being run from the build directory and
608                  * weren't started with special privileges, and we were
609                  * able to determine the directory in which the program
610                  * was found, so use that.
611                  */
612                 datafile_dir = progfile_dir;
613         } else {
614                 /*
615                  * Return the directory specified when the build was
616                  * configured, prepending the run path prefix if it exists.
617                  */
618                 if (getenv("WIRESHARK_DATA_DIR") && !started_with_special_privs()) {
619                         /*
620                          * The user specified a different directory for data files
621                          * and we aren't running with special privileges.
622                          * XXX - We might be able to dispense with the priv check
623                          */
624                         datafile_dir = g_strdup(getenv("WIRESHARK_DATA_DIR"));
625                 } else {
626                         datafile_dir = DATAFILE_DIR;
627                 }
628         }
629
630 #endif
631         return datafile_dir;
632 }
633
634 #ifdef HAVE_PLUGINS
635 /*
636  * Find the directory where the plugins are stored.
637  *
638  * On Windows, we use the "plugin" subdirectory of the datafile directory.
639  *
640  * On UN*X, we use the PLUGIN_DIR value supplied by the configure
641  * script, unless we think we're being run from the build directory,
642  * in which case we use the "plugin" subdirectory of the datafile directory.
643  *
644  * In both cases, we then use the subdirectory of that directory whose
645  * name is the version number.
646  *
647  * XXX - if we think we're being run from the build directory, perhaps we
648  * should have the plugin code not look in the version subdirectory
649  * of the plugin directory, but look in all of the subdirectories
650  * of the plugin directory, so it can just fetch the plugins built
651  * as part of the build process.
652  */
653 static const char *plugin_dir = NULL;
654
655 static void
656 init_plugin_dir(void)
657 {
658 #ifdef _WIN32
659         /*
660          * On Windows, the data file directory is the installation
661          * directory; the plugins are stored under it.
662          *
663          * Assume we're running the installed version of Wireshark;
664          * on Windows, the data file directory is the directory
665          * in which the Wireshark binary resides.
666          */
667         plugin_dir = g_strdup_printf("%s\\plugins\\%s", get_datafile_dir(),
668             VERSION);
669
670         /*
671          * Make sure that pathname refers to a directory.
672          */
673         if (test_for_directory(plugin_dir) != EISDIR) {
674                 /*
675                  * Either it doesn't refer to a directory or it
676                  * refers to something that doesn't exist.
677                  *
678                  * Assume that means we're running a version of
679                  * Wireshark we've built in a build directory,
680                  * in which case {datafile dir}\plugins is the
681                  * top-level plugins source directory, and use
682                  * that directory and set the "we're running in
683                  * a build directory" flag, so the plugin
684                  * scanner will check all subdirectories of that
685                  * directory for plugins.
686                  */
687                 g_free( (gpointer) plugin_dir);
688                 plugin_dir = g_strdup_printf("%s\\plugins", get_datafile_dir());
689                 running_in_build_directory_flag = TRUE;
690         }
691 #else
692         if (running_in_build_directory_flag) {
693                 /*
694                  * We're (probably) being run from the build directory and
695                  * weren't started with special privileges, so we'll use
696                  * the "plugins" subdirectory of the datafile directory
697                  * (the datafile directory is the build directory).
698                  */
699                 plugin_dir = g_strdup_printf("%s/plugins", get_datafile_dir());
700         } else {
701                 if (getenv("WIRESHARK_PLUGIN_DIR") && !started_with_special_privs()) {
702                         /*
703                          * The user specified a different directory for plugins
704                          * and we aren't running with special privileges.
705                          */
706                         plugin_dir = g_strdup(getenv("WIRESHARK_PLUGIN_DIR"));
707                 } else {
708                         plugin_dir = PLUGIN_DIR;
709                 }
710         }
711 #endif
712 }
713 #endif /* HAVE_PLUGINS */
714
715 /*
716  * Get the directory in which the plugins are stored.
717  */
718 const char *
719 get_plugin_dir(void)
720 {
721 #ifdef HAVE_PLUGINS
722         if (!plugin_dir) init_plugin_dir();
723         return plugin_dir;
724 #else
725         return NULL;
726 #endif
727 }
728
729 /*
730  * Get the flag indicating whether we're running from a build
731  * directory.
732  */
733 gboolean
734 running_in_build_directory(void)
735 {
736         return running_in_build_directory_flag;
737 }
738
739 /*
740  * Get the directory in which files that, at least on UNIX, are
741  * system files (such as "/etc/ethers") are stored; on Windows,
742  * there's no "/etc" directory, so we get them from the global
743  * configuration and data file directory.
744  */
745 const char *
746 get_systemfile_dir(void)
747 {
748 #ifdef _WIN32
749         return get_datafile_dir();
750 #else
751         return "/etc";
752 #endif
753 }
754
755 /*
756  * Name of directory, under the user's home directory, in which
757  * personal configuration files are stored.
758  */
759 #ifdef _WIN32
760 #define PF_DIR "Wireshark"
761 #else
762 /*
763  * XXX - should this be ".libepan"? For backwards-compatibility, I'll keep
764  * it ".wireshark" for now.
765  */
766 #define PF_DIR ".wireshark"
767 #endif
768
769 #ifdef _WIN32
770 /* utf8 version of getenv, needed to get win32 filename paths */
771 char *getenv_utf8(const char *varname)
772 {
773         char *envvar;
774         wchar_t *envvarw;
775         wchar_t *varnamew;
776
777         envvar = getenv(varname);
778
779         /* since GLib 2.6 we need an utf8 version of the filename */
780 #if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
781         /* using the wide char version of getenv should work under all circumstances */
782
783         /* convert given varname to utf16, needed by _wgetenv */
784         varnamew = g_utf8_to_utf16(varname, -1, NULL, NULL, NULL);
785         if (varnamew == NULL) {
786                 return envvar;
787         }
788
789         /* use wide char version of getenv */
790         envvarw = _wgetenv(varnamew);
791         g_free(varnamew);
792         if (envvarw == NULL) {
793                 return envvar;
794         }
795
796         /* convert value to utf8 */
797         envvar = g_utf16_to_utf8(envvarw, -1, NULL, NULL, NULL);
798         /* XXX - memleak */
799 #endif
800
801         return envvar;
802 }
803 #endif
804
805 void
806 set_profile_name(const gchar *profilename)
807 {
808         if (persconfprofile) {
809                 g_free (persconfprofile);
810         }
811
812         if (profilename && strlen(profilename) > 0 &&
813             strcmp(profilename, DEFAULT_PROFILE) != 0) {
814                 persconfprofile = g_strdup (profilename);
815         } else {
816                 /* Default Profile */
817                 persconfprofile = NULL;
818         }
819 }
820
821 const char *
822 get_profile_name(void)
823 {
824         if (persconfprofile) {
825                 return persconfprofile;
826         } else {
827                 return DEFAULT_PROFILE;
828         }
829 }
830
831 /*
832  * Get the directory in which personal configuration files reside;
833  * in UNIX-compatible systems, it's ".wireshark", under the user's home
834  * directory, and on Windows systems, it's "Wireshark", under %APPDATA%
835  * or, if %APPDATA% isn't set, it's "%USERPROFILE%\Application Data"
836  * (which is what %APPDATA% normally is on Windows 2000).
837  */
838 static const char *
839 get_persconffile_dir_no_profile(void)
840 {
841 #ifdef _WIN32
842         char *appdatadir;
843         char *userprofiledir;
844         char *u3appdatapath;
845 #else
846         const char *homedir;
847         struct passwd *pwd;
848 #endif
849
850         /* Return the cached value, if available */
851         if (persconffile_dir != NULL)
852                 return persconffile_dir;
853
854 #ifdef _WIN32
855         /*
856          * See if we are running in a U3 environment.
857          */
858         u3appdatapath = getenv_utf8("U3_APP_DATA_PATH");
859         if (u3appdatapath != NULL) {
860                 /*
861                  * We are; use the U3 application data path.
862                  */
863                 persconffile_dir = u3appdatapath;
864         } else {
865                 /*
866                  * Use %APPDATA% or %USERPROFILE%, so that configuration
867                  * files are stored in the user profile, rather than in
868                  * the home directory.  The Windows convention is to store
869                  * configuration information in the user profile, and doing
870                  * so means you can use Wireshark even if the home directory
871                  * is an inaccessible network drive.
872                  */
873                 appdatadir = getenv_utf8("APPDATA");
874                 if (appdatadir != NULL) {
875                         /*
876                          * Concatenate %APPDATA% with "\Wireshark".
877                          */
878                         persconffile_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
879                                                            appdatadir, PF_DIR);
880                 } else {
881                         /*
882                          * OK, %APPDATA% wasn't set, so use
883                          * %USERPROFILE%\Application Data.
884                          */
885                         userprofiledir = getenv_utf8("USERPROFILE");
886                         if (userprofiledir != NULL) {
887                                 persconffile_dir = g_strdup_printf(
888                                     "%s" G_DIR_SEPARATOR_S "Application Data" G_DIR_SEPARATOR_S "%s",
889                                     userprofiledir, PF_DIR);
890                         } else {
891                                 /*
892                                  * Give up and use "C:".
893                                  */
894                                 persconffile_dir = g_strdup_printf("C:" G_DIR_SEPARATOR_S "%s", PF_DIR);
895                         }
896                 }
897         }
898 #else
899         /*
900          * If $HOME is set, use that.
901          */
902         homedir = getenv("HOME");
903         if (homedir == NULL) {
904                 /*
905                  * Get their home directory from the password file.
906                  * If we can't even find a password file entry for them,
907                  * use "/tmp".
908                  */
909                 pwd = getpwuid(getuid());
910                 if (pwd != NULL) {
911                         /*
912                          * This is cached, so we don't need to worry
913                          * about allocating multiple ones of them.
914                          */
915                         homedir = g_strdup(pwd->pw_dir);
916                 } else
917                         homedir = "/tmp";
918         }
919         persconffile_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", homedir, PF_DIR);
920 #endif
921
922         return persconffile_dir;
923 }
924
925 const char *
926 get_profiles_dir(void)
927 {
928         static char *profiles_dir = NULL;
929
930         if (profiles_dir) {
931                 g_free (profiles_dir);
932         }
933
934         profiles_dir = g_strdup_printf ("%s%s%s", get_persconffile_dir_no_profile (),
935                                         G_DIR_SEPARATOR_S, PROFILES_DIR);
936
937         return profiles_dir;
938 }
939
940 static const char *
941 get_persconffile_dir(const gchar *profilename)
942 {
943         static char *persconffile_profile_dir = NULL;
944
945         if (persconffile_profile_dir) {
946                 g_free (persconffile_profile_dir);
947         }
948
949         if (profilename && strlen(profilename) > 0 &&
950             strcmp(profilename, DEFAULT_PROFILE) != 0) {
951           persconffile_profile_dir = g_strdup_printf ("%s%s%s", get_profiles_dir (),
952                                                       G_DIR_SEPARATOR_S, profilename);
953         } else {
954           persconffile_profile_dir = g_strdup_printf (get_persconffile_dir_no_profile ());
955         }
956
957         return persconffile_profile_dir;
958 }
959
960 gboolean
961 profile_exists(const gchar *profilename)
962 {
963         if (test_for_directory (get_persconffile_dir (profilename)) == EISDIR) {
964                 return TRUE;
965         }
966
967         return FALSE;
968 }
969
970 static int
971 delete_directory (const char *directory, char **pf_dir_path_return)
972 {
973         ETH_DIR *dir;
974         ETH_DIRENT *file;
975         gchar *filename;
976         int ret = 0;
977
978         if ((dir = eth_dir_open(directory, 0, NULL)) != NULL) {
979                 while ((file = eth_dir_read_name(dir)) != NULL) {
980                         filename = g_strdup_printf ("%s%s%s", directory, G_DIR_SEPARATOR_S,
981                                                     eth_dir_get_name(file));
982                         if (test_for_directory(filename) != EISDIR) {
983                                 ret = eth_remove(filename);
984 #if 0
985                         } else {
986                                 /* The user has manually created a directory in the profile directory */
987                                 /* I do not want to delete the directory recursively yet */
988                                 ret = delete_directory (filename, pf_dir_path_return);
989 #endif
990                         }
991                         if (ret != 0) {
992                                 *pf_dir_path_return = filename;
993                                 break;
994                         }
995                         g_free (filename);
996                 }
997                 eth_dir_close(dir);
998         }
999
1000         if (ret == 0 && (ret = eth_remove(directory)) != 0) {
1001                 *pf_dir_path_return = g_strdup (directory);
1002         }
1003
1004         return ret;
1005 }
1006
1007 int
1008 delete_persconffile_profile(const char *profilename, char **pf_dir_path_return)
1009 {
1010         const char *profile_dir = get_persconffile_dir(profilename);
1011         int ret = 0;
1012
1013         if (test_for_directory (profile_dir) == EISDIR) {
1014                 ret = delete_directory (profile_dir, pf_dir_path_return);
1015         }
1016
1017         return ret;
1018 }
1019
1020 int
1021 rename_persconffile_profile(const char *fromname, const char *toname,
1022                             char **pf_from_dir_path_return, char **pf_to_dir_path_return)
1023 {
1024         char *from_dir = g_strdup (get_persconffile_dir(fromname));
1025         char *to_dir = g_strdup (get_persconffile_dir(toname));
1026         int ret = 0;
1027
1028         ret = eth_rename (from_dir, to_dir);
1029         if (ret != 0) {
1030                 *pf_from_dir_path_return = g_strdup (from_dir);
1031                 *pf_to_dir_path_return = g_strdup (to_dir);
1032         }
1033
1034         g_free (from_dir);
1035         g_free (to_dir);
1036
1037         return ret;
1038 }
1039
1040 /*
1041  * Create the directory that holds personal configuration files, if
1042  * necessary.  If we attempted to create it, and failed, return -1 and
1043  * set "*pf_dir_path_return" to the pathname of the directory we failed
1044  * to create (it's g_mallocated, so our caller should free it); otherwise,
1045  * return 0.
1046  */
1047 int
1048 create_persconffile_profile(const char *profilename, char **pf_dir_path_return)
1049 {
1050         const char *pf_dir_path;
1051 #ifdef _WIN32
1052         char *pf_dir_path_copy, *pf_dir_parent_path;
1053         size_t pf_dir_parent_path_len;
1054 #endif
1055         struct stat s_buf;
1056         int ret;
1057
1058         if (profilename) {
1059                 /*
1060                  * Check if profiles directory exists.
1061                  * If not then create it.
1062                  */
1063                 pf_dir_path = get_profiles_dir ();
1064                 if (eth_stat(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
1065                         ret = eth_mkdir(pf_dir_path, 0755);
1066                         if (ret == -1) {
1067                                 *pf_dir_path_return = g_strdup(pf_dir_path);
1068                                 return ret;
1069                         }
1070                 }
1071         }
1072
1073         pf_dir_path = get_persconffile_dir(profilename);
1074         if (eth_stat(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
1075 #ifdef _WIN32
1076                 /*
1077                  * Does the parent directory of that directory
1078                  * exist?  %APPDATA% may not exist even though
1079                  * %USERPROFILE% does.
1080                  *
1081                  * We check for the existence of the directory
1082                  * by first checking whether the parent directory
1083                  * is just a drive letter and, if it's not, by
1084                  * doing a "stat()" on it.  If it's a drive letter,
1085                  * or if the "stat()" succeeds, we assume it exists.
1086                  */
1087                 pf_dir_path_copy = g_strdup(pf_dir_path);
1088                 pf_dir_parent_path = get_dirname(pf_dir_path_copy);
1089                 pf_dir_parent_path_len = strlen(pf_dir_parent_path);
1090                 if (pf_dir_parent_path_len > 0
1091                     && pf_dir_parent_path[pf_dir_parent_path_len - 1] != ':'
1092                     && eth_stat(pf_dir_parent_path, &s_buf) != 0) {
1093                         /*
1094                          * No, it doesn't exist - make it first.
1095                          */
1096                         ret = eth_mkdir(pf_dir_parent_path, 0755);
1097                         if (ret == -1) {
1098                                 *pf_dir_path_return = pf_dir_parent_path;
1099                                 return -1;
1100                         }
1101                 }
1102                 g_free(pf_dir_path_copy);
1103                 ret = eth_mkdir(pf_dir_path, 0755);
1104 #else
1105                 ret = eth_mkdir(pf_dir_path, 0755);
1106 #endif
1107         } else {
1108                 /*
1109                  * Something with that pathname exists; if it's not
1110                  * a directory, we'll get an error if we try to put
1111                  * something in it, so we don't fail here, we wait
1112                  * for that attempt fo fail.
1113                  */
1114                 ret = 0;
1115         }
1116         if (ret == -1)
1117                 *pf_dir_path_return = g_strdup(pf_dir_path);
1118         return ret;
1119 }
1120
1121 int
1122 create_persconffile_dir(char **pf_dir_path_return)
1123 {
1124   return create_persconffile_profile(persconfprofile, pf_dir_path_return);
1125 }
1126
1127 /*
1128  * Get the (default) directory in which personal data is stored.
1129  *
1130  * On Win32, this is the "My Documents" folder in the personal profile.
1131  * On UNIX this is simply the current directory.
1132  * On a U3 device this is "$U3_DEVICE_DOCUMENT_PATH\My Captures" folder.
1133  */
1134 /* XXX - should this and the get_home_dir() be merged? */
1135 extern char *
1136 get_persdatafile_dir(void)
1137 {
1138 #ifdef _WIN32
1139         char *u3devicedocumentpath;
1140         TCHAR tszPath[MAX_PATH];
1141         char *szPath;
1142         BOOL bRet;
1143
1144
1145         /* Return the cached value, if available */
1146         if (persdatafile_dir != NULL)
1147                 return persdatafile_dir;
1148
1149         /*
1150          * See if we are running in a U3 environment.
1151          */
1152         u3devicedocumentpath = getenv_utf8("U3_DEVICE_DOCUMENT_PATH");
1153
1154         if (u3devicedocumentpath != NULL) {
1155
1156           /* the "My Captures" sub-directory is created (if it doesn't exist)
1157                  by u3util.exe when the U3 Wireshark is first run */
1158
1159           szPath = g_strdup_printf("%s%s", u3devicedocumentpath, U3_MY_CAPTURES);
1160
1161           persdatafile_dir = szPath;
1162           return szPath;
1163
1164                 } else {
1165         /* Hint: SHGetFolderPath is not available on MSVC 6 - without Platform SDK */
1166         bRet = SHGetSpecialFolderPath(NULL, tszPath, CSIDL_PERSONAL, FALSE);
1167         if(bRet == TRUE) {
1168                 szPath = utf_16to8(tszPath);
1169                 persdatafile_dir = szPath;
1170                 return szPath;
1171         } else {
1172                 return "";
1173         }
1174 }
1175 #else
1176   return "";
1177 #endif
1178 }
1179
1180 #ifdef _WIN32
1181 /*
1182  * Returns the user's home directory on Win32.
1183  */
1184 static const char *
1185 get_home_dir(void)
1186 {
1187         static const char *home = NULL;
1188         char *homedrive, *homepath;
1189         char *homestring;
1190         char *lastsep;
1191
1192         /* Return the cached value, if available */
1193         if (home)
1194                 return home;
1195
1196         /*
1197          * XXX - should we use USERPROFILE anywhere in this process?
1198          * Is there a chance that it might be set but one or more of
1199          * HOMEDRIVE or HOMEPATH isn't set?
1200          */
1201         homedrive = getenv_utf8("HOMEDRIVE");
1202         if (homedrive != NULL) {
1203                 homepath = getenv_utf8("HOMEPATH");
1204                 if (homepath != NULL) {
1205                         /*
1206                          * This is cached, so we don't need to worry about
1207                          * allocating multiple ones of them.
1208                          */
1209                         homestring = g_strdup_printf("%s%s", homedrive, homepath);
1210
1211                         /*
1212                          * Trim off any trailing slash or backslash.
1213                          */
1214                         lastsep = find_last_pathname_separator(homestring);
1215                         if (lastsep != NULL && *(lastsep + 1) == '\0') {
1216                                 /*
1217                                  * Last separator is the last character
1218                                  * in the string.  Nuke it.
1219                                  */
1220                                 *lastsep = '\0';
1221                         }
1222                         home = homestring;
1223                 } else
1224                         home = homedrive;
1225         } else {
1226                 /*
1227                  * Give up and use C:.
1228                  */
1229                 home = "C:";
1230         }
1231
1232         return home;
1233 }
1234 #endif
1235
1236 /*
1237  * Construct the path name of a personal configuration file, given the
1238  * file name.
1239  *
1240  * On Win32, if "for_writing" is FALSE, we check whether the file exists
1241  * and, if not, construct a path name relative to the ".wireshark"
1242  * subdirectory of the user's home directory, and check whether that
1243  * exists; if it does, we return that, so that configuration files
1244  * from earlier versions can be read.
1245  *
1246  * The returned file name was g_malloc()'d so it must be g_free()d when the
1247  * caller is done with it.
1248  */
1249 char *
1250 get_persconffile_path(const char *filename, gboolean from_profile, gboolean for_writing
1251 #ifndef _WIN32
1252         _U_
1253 #endif
1254 )
1255 {
1256         char *path;
1257 #ifdef _WIN32
1258         struct stat s_buf;
1259         char *old_path;
1260 #endif
1261
1262         if (from_profile) {
1263           path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
1264                                  get_persconffile_dir(persconfprofile), filename);
1265         } else {
1266           path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
1267                                  get_persconffile_dir(NULL), filename);
1268         }
1269 #ifdef _WIN32
1270         if (!for_writing) {
1271                 if (eth_stat(path, &s_buf) != 0 && errno == ENOENT) {
1272                         /*
1273                          * OK, it's not in the personal configuration file
1274                          * directory; is it in the ".wireshark" subdirectory
1275                          * of their home directory?
1276                          */
1277                         old_path = g_strdup_printf(
1278                             "%s" G_DIR_SEPARATOR_S ".wireshark" G_DIR_SEPARATOR_S "%s",
1279                             get_home_dir(), filename);
1280                         if (eth_stat(old_path, &s_buf) == 0) {
1281                                 /*
1282                                  * OK, it exists; return it instead.
1283                                  */
1284                                 g_free(path);
1285                                 path = old_path;
1286                         }
1287                 }
1288         }
1289 #endif
1290
1291         return path;
1292 }
1293
1294 /*
1295  * process command line option belonging to the filesystem settings
1296  * (move this e.g. to main.c and have set_persconffile_dir() instead in this file?)
1297  */
1298 int
1299 filesystem_opt(int opt _U_, const char *optarg)
1300 {
1301         gchar *p, *colonp;
1302
1303         colonp = strchr(optarg, ':');
1304         if (colonp == NULL) {
1305                 return 1;
1306         }
1307
1308         p = colonp;
1309         *p++ = '\0';
1310
1311         /*
1312         * Skip over any white space (there probably won't be any, but
1313         * as we allow it in the preferences file, we might as well
1314         * allow it here).
1315         */
1316         while (isspace((guchar)*p))
1317         p++;
1318         if (*p == '\0') {
1319                 /*
1320                  * Put the colon back, so if our caller uses, in an
1321                  * error message, the string they passed us, the message
1322                  * looks correct.
1323                  */
1324                 *colonp = ':';
1325                 return 1;
1326         }
1327
1328         /* directory should be existing */
1329         /* XXX - is this a requirement? */
1330         if(test_for_directory(p) != EISDIR) {
1331                 /*
1332                  * Put the colon back, so if our caller uses, in an
1333                  * error message, the string they passed us, the message
1334                  * looks correct.
1335                  */
1336                 *colonp = ':';
1337                 return 1;
1338         }
1339
1340         if (strcmp(optarg,"persconf") == 0) {
1341                 persconffile_dir = p;
1342         } else if (strcmp(optarg,"persdata") == 0) {
1343                 persdatafile_dir = p;
1344                 /* XXX - might need to add the temp file path */
1345         } else {
1346                 return 1;
1347         }
1348         *colonp = ':'; /* put the colon back */
1349         return 0;
1350 }
1351
1352 /*
1353  * Construct the path name of a global configuration file, given the
1354  * file name.
1355  *
1356  * The returned file name was g_malloc()'d so it must be g_free()d when the
1357  * caller is done with it.
1358  */
1359 char *
1360 get_datafile_path(const char *filename)
1361 {
1362
1363         return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", get_datafile_dir(),
1364                 filename);
1365 }
1366
1367 /* Delete a file */
1368 gboolean
1369 deletefile(const char *path)
1370 {
1371         return eth_unlink(path) == 0;
1372 }
1373
1374 /*
1375  * Construct and return the path name of a file in the
1376  * appropriate temporary file directory.
1377  */
1378 char *get_tempfile_path(const char *filename)
1379 {
1380         return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", g_get_tmp_dir(), filename);
1381 }
1382
1383 /*
1384  * Return an error message for UNIX-style errno indications on open or
1385  * create operations.
1386  */
1387 const char *
1388 file_open_error_message(int err, gboolean for_writing)
1389 {
1390         const char *errmsg;
1391         static char errmsg_errno[1024+1];
1392
1393         switch (err) {
1394
1395         case ENOENT:
1396                 if (for_writing)
1397                         errmsg = "The path to the file \"%s\" doesn't exist.";
1398                 else
1399                         errmsg = "The file \"%s\" doesn't exist.";
1400                 break;
1401
1402         case EACCES:
1403                 if (for_writing)
1404                         errmsg = "You don't have permission to create or write to the file \"%s\".";
1405                 else
1406                         errmsg = "You don't have permission to read the file \"%s\".";
1407                 break;
1408
1409         case EISDIR:
1410                 errmsg = "\"%s\" is a directory (folder), not a file.";
1411                 break;
1412
1413         case ENOSPC:
1414                 errmsg = "The file \"%s\" could not be created because there is no space left on the file system.";
1415                 break;
1416
1417 #ifdef EDQUOT
1418         case EDQUOT:
1419                 errmsg = "The file \"%s\" could not be created because you are too close to, or over, your disk quota.";
1420                 break;
1421 #endif
1422
1423         case EINVAL:
1424                 errmsg = "The file \"%s\" could not be created because an invalid filename was specified.";
1425                 break;
1426
1427         default:
1428                 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1429                                 "The file \"%%s\" could not be %s: %s.",
1430                                 for_writing ? "created" : "opened",
1431                                 strerror(err));
1432                 errmsg = errmsg_errno;
1433                 break;
1434         }
1435         return errmsg;
1436 }
1437
1438 /*
1439  * Return an error message for UNIX-style errno indications on write
1440  * operations.
1441  */
1442 const char *
1443 file_write_error_message(int err)
1444 {
1445         const char *errmsg;
1446         static char errmsg_errno[1024+1];
1447
1448         switch (err) {
1449
1450         case ENOSPC:
1451                 errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1452                 break;
1453
1454 #ifdef EDQUOT
1455         case EDQUOT:
1456                 errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1457                 break;
1458 #endif
1459
1460         default:
1461                 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1462                     "An error occurred while writing to the file \"%%s\": %s.",
1463                     strerror(err));
1464                 errmsg = errmsg_errno;
1465                 break;
1466         }
1467         return errmsg;
1468 }
1469
1470
1471 gboolean
1472 file_exists(const char *fname)
1473 {
1474         struct stat   file_stat;
1475
1476 #ifdef _WIN32
1477         /*
1478          * This is a bit tricky on win32. The st_ino field is documented as:
1479          * "The inode, and therefore st_ino, has no meaning in the FAT, ..."
1480          * but it *is* set to zero if stat() returns without an error,
1481          * so this is working, but maybe not quite the way expected. ULFL
1482          */
1483         file_stat.st_ino = 1;   /* this will make things work if an error occured */
1484         eth_stat(fname, &file_stat);
1485         if (file_stat.st_ino == 0) {
1486                 return TRUE;
1487         } else {
1488                 return FALSE;
1489         }
1490 #else
1491         if (eth_stat(fname, &file_stat) != 0 && errno == ENOENT) {
1492                 return FALSE;
1493         } else {
1494                 return TRUE;
1495         }
1496 #endif
1497 }
1498
1499 /*
1500  * Check that the from file is not the same as to file
1501  * We do it here so we catch all cases ...
1502  * Unfortunately, the file requester gives us an absolute file
1503  * name and the read file name may be relative (if supplied on
1504  * the command line), so we can't just compare paths. From Joerg Mayer.
1505  */
1506 gboolean
1507 files_identical(const char *fname1, const char *fname2)
1508 {
1509         /* Two different implementations, because:
1510          *
1511          * - _fullpath is not available on UN*X, so we can't get full
1512          *   paths and compare them (which wouldn't work with hard links
1513          *   in any case);
1514          *
1515          * - st_ino isn't filled in with a meaningful value on Windows.
1516          */
1517 #ifdef _WIN32
1518         char full1[MAX_PATH], full2[MAX_PATH];
1519
1520         /*
1521          * Get the absolute full paths of the file and compare them.
1522          * That won't work if you have hard links, but those aren't
1523          * much used on Windows, even though NTFS supports them.
1524          *
1525          * XXX - will _fullpath work with UNC?
1526          */
1527         if( _fullpath( full1, fname1, MAX_PATH ) == NULL ) {
1528                 return FALSE;
1529         }
1530
1531         if( _fullpath( full2, fname2, MAX_PATH ) == NULL ) {
1532                 return FALSE;
1533         }
1534
1535         if(strcmp(full1, full2) == 0) {
1536                 return TRUE;
1537         } else {
1538                 return FALSE;
1539         }
1540 #else
1541         struct stat   filestat1, filestat2;
1542
1543         /*
1544          * Compare st_dev and st_ino.
1545          */
1546         if (eth_stat(fname1, &filestat1) == -1)
1547                 return FALSE;   /* can't get info about the first file */
1548         if (eth_stat(fname2, &filestat2) == -1)
1549                 return FALSE;   /* can't get info about the second file */
1550         return (filestat1.st_dev == filestat2.st_dev &&
1551                 filestat1.st_ino == filestat2.st_ino);
1552 #endif
1553 }
1554
1555 /*
1556  * Editor modelines
1557  *
1558  * Local Variables:
1559  * c-basic-offset: 4
1560  * tab-width: 4
1561  * indent-tabs-mode: tabs
1562  * End:
1563  *
1564  * ex: set shiftwidth=4 tabstop=4 noexpandtab
1565  * :indentSize=4:tabSize=4:noTabs=false:
1566  */
1567