Remove all preferences related to enabling/disabling heuristic dissectors.
[metze/wireshark/wip.git] / epan / disabled_protos.c
1 /* disabled_protos.c
2  * Code for reading and writing the disabled protocols file.
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
33 #include <glib.h>
34
35 #include <wsutil/filesystem.h>
36 #include <epan/proto.h>
37 #include <epan/packet.h>
38
39 #include "disabled_protos.h"
40 #include <wsutil/file_util.h>
41
42 #define PROTOCOLS_FILE_NAME             "disabled_protos"
43 #define HEURISTICS_FILE_NAME            "heuristic_protos"
44
45 /*
46  * Item in a list of disabled protocols.
47  */
48 typedef struct {
49   char *name;           /* protocol name */
50 } protocol_def;
51
52 /*
53  * Item in a list of heuristic dissectors and their enabled state.
54  */
55 typedef struct {
56   char *name;           /* heuristic short name */
57   gboolean enabled;     /* heuristc enabled */
58 } heur_protocol_def;
59
60 /*
61  * List of disabled protocols
62  */
63 static GList *global_disabled_protos = NULL;
64 static GList *disabled_protos = NULL;
65 /*
66  * List of disabled heuristics
67  */
68 static GList *global_disabled_heuristics = NULL;
69 static GList *disabled_heuristics = NULL;
70
71 #define INIT_BUF_SIZE   128
72
73 static void
74 discard_existing_list (GList **flp)
75 {
76   GList      *fl_ent;
77   protocol_def *prot;
78
79   if (*flp != NULL) {
80     fl_ent = g_list_first(*flp);
81     while (fl_ent != NULL) {
82       prot = (protocol_def *) fl_ent->data;
83       g_free(prot->name);
84       g_free(prot);
85       fl_ent = fl_ent->next;
86     }
87     g_list_free(*flp);
88     *flp = NULL;
89   }
90 }
91
92 static void
93 heur_discard_existing_list (GList **flp)
94 {
95   GList      *fl_ent;
96   heur_protocol_def *prot;
97
98   if (*flp != NULL) {
99     fl_ent = g_list_first(*flp);
100     while (fl_ent != NULL) {
101       prot = (heur_protocol_def *) fl_ent->data;
102       g_free(prot->name);
103       g_free(prot);
104       fl_ent = fl_ent->next;
105     }
106     g_list_free(*flp);
107     *flp = NULL;
108   }
109 }
110
111 /*
112  * Read in a list of disabled protocols.
113  *
114  * On success, "*pref_path_return" is set to NULL.
115  * On error, "*pref_path_return" is set to point to the pathname of
116  * the file we tried to read - it should be freed by our caller -
117  * and "*open_errno_return" is set to the error if an open failed
118  * or "*read_errno_return" is set to the error if a read failed.
119  */
120
121 static int read_disabled_protos_list_file(const char *ff_path, FILE *ff,
122                                           GList **flp);
123
124 void
125 read_disabled_protos_list(char **gpath_return, int *gopen_errno_return,
126                           int *gread_errno_return,
127                           char **path_return, int *open_errno_return,
128                           int *read_errno_return)
129 {
130   int         err;
131   char       *gff_path, *ff_path;
132   FILE       *ff;
133
134   /* Construct the pathname of the global disabled protocols file. */
135   gff_path = get_datafile_path(PROTOCOLS_FILE_NAME);
136
137   /* If we already have a list of protocols, discard it. */
138   discard_existing_list (&global_disabled_protos);
139
140   /* Read the global disabled protocols file, if it exists. */
141   *gpath_return = NULL;
142   if ((ff = ws_fopen(gff_path, "r")) != NULL) {
143     /* We succeeded in opening it; read it. */
144     err = read_disabled_protos_list_file(gff_path, ff,
145                                          &global_disabled_protos);
146     if (err != 0) {
147       /* We had an error reading the file; return the errno and the
148          pathname, so our caller can report the error. */
149       *gopen_errno_return = 0;
150       *gread_errno_return = err;
151       *gpath_return = gff_path;
152     } else
153       g_free(gff_path);
154     fclose(ff);
155   } else {
156     /* We failed to open it.  If we failed for some reason other than
157        "it doesn't exist", return the errno and the pathname, so our
158        caller can report the error. */
159     if (errno != ENOENT) {
160       *gopen_errno_return = errno;
161       *gread_errno_return = 0;
162       *gpath_return = gff_path;
163     } else
164       g_free(gff_path);
165   }
166
167   /* Construct the pathname of the user's disabled protocols file. */
168   ff_path = get_persconffile_path(PROTOCOLS_FILE_NAME, TRUE);
169
170   /* If we already have a list of protocols, discard it. */
171   discard_existing_list (&disabled_protos);
172
173   /* Read the user's disabled protocols file, if it exists. */
174   *path_return = NULL;
175   if ((ff = ws_fopen(ff_path, "r")) != NULL) {
176     /* We succeeded in opening it; read it. */
177     err = read_disabled_protos_list_file(ff_path, ff, &disabled_protos);
178     if (err != 0) {
179       /* We had an error reading the file; return the errno and the
180          pathname, so our caller can report the error. */
181       *open_errno_return = 0;
182       *read_errno_return = err;
183       *path_return = ff_path;
184     } else
185       g_free(ff_path);
186     fclose(ff);
187   } else {
188     /* We failed to open it.  If we failed for some reason other than
189        "it doesn't exist", return the errno and the pathname, so our
190        caller can report the error. */
191     if (errno != ENOENT) {
192       *open_errno_return = errno;
193       *read_errno_return = 0;
194       *path_return = ff_path;
195     } else
196       g_free(ff_path);
197   }
198 }
199
200 static int
201 read_disabled_protos_list_file(const char *ff_path, FILE *ff,
202                                GList **flp)
203 {
204   protocol_def *prot;
205   int         c;
206   char       *prot_name;
207   int         prot_name_len;
208   int         prot_name_index;
209   int         line = 1;
210
211
212   /* Allocate the protocol name buffer. */
213   prot_name_len = INIT_BUF_SIZE;
214   prot_name = (char *)g_malloc(prot_name_len + 1);
215
216   for (line = 1; ; line++) {
217     /* Lines in a disabled protocol file contain the "filter name" of
218        a protocol to be disabled. */
219
220     /* Skip over leading white space, if any. */
221     while ((c = getc(ff)) != EOF && g_ascii_isspace(c)) {
222       if (c == '\n') {
223         /* Blank line. */
224         continue;
225       }
226     }
227
228     if (c == EOF) {
229       if (ferror(ff))
230         goto error;     /* I/O error */
231       else
232         break;  /* Nothing more to read */
233     }
234     ungetc(c, ff);      /* Unread the non-white-space character. */
235
236     /* Get the name of the protocol. */
237     prot_name_index = 0;
238     for (;;) {
239       c = getc(ff);
240       if (c == EOF)
241         break;  /* End of file, or I/O error */
242       if (g_ascii_isspace(c))
243         break;  /* Trailing white space, or end of line. */
244       if (c == '#')
245         break;  /* Start of comment, running to end of line. */
246       /* Add this character to the protocol name string. */
247       if (prot_name_index >= prot_name_len) {
248         /* protocol name buffer isn't long enough; double its length. */
249         prot_name_len *= 2;
250         prot_name = (char *)g_realloc(prot_name, prot_name_len + 1);
251       }
252       prot_name[prot_name_index] = c;
253       prot_name_index++;
254     }
255
256     if (g_ascii_isspace(c) && c != '\n') {
257       /* Skip over trailing white space. */
258       while ((c = getc(ff)) != EOF && c != '\n' && g_ascii_isspace(c))
259         ;
260       if (c != EOF && c != '\n' && c != '#') {
261         /* Non-white-space after the protocol name; warn about it,
262            in case we come up with a reason to use it. */
263         g_warning("'%s' line %d has extra stuff after the protocol name.",
264                   ff_path, line);
265       }
266     }
267     if (c != EOF && c != '\n') {
268       /* Skip to end of line. */
269       while ((c = getc(ff)) != EOF && c != '\n')
270         ;
271     }
272
273     if (c == EOF) {
274       if (ferror(ff))
275         goto error;     /* I/O error */
276       else {
277         /* EOF, not error; no newline seen before EOF */
278         g_warning("'%s' line %d doesn't have a newline.", ff_path,
279                   line);
280       }
281       break;    /* nothing more to read */
282     }
283
284     /* Null-terminate the protocol name. */
285     if (prot_name_index >= prot_name_len) {
286       /* protocol name buffer isn't long enough; double its length. */
287       prot_name_len *= 2;
288       prot_name = (char *)g_realloc(prot_name, prot_name_len + 1);
289     }
290     prot_name[prot_name_index] = '\0';
291
292     /* Add the new protocol to the list of disabled protocols */
293     prot         = (protocol_def *) g_malloc(sizeof(protocol_def));
294     prot->name   = g_strdup(prot_name);
295     *flp = g_list_append(*flp, prot);
296   }
297   g_free(prot_name);
298   return 0;
299
300 error:
301   g_free(prot_name);
302   return errno;
303 }
304
305 /*
306  * Disable protocols as per the stored configuration
307  */
308 void
309 set_disabled_protos_list(void)
310 {
311   gint i;
312   GList *fl_ent;
313   protocol_def *prot;
314
315   /*
316    * assume all protocols are enabled by default
317    */
318   if (disabled_protos == NULL)
319     goto skip;
320
321   fl_ent = g_list_first(disabled_protos);
322
323   while (fl_ent != NULL) {
324     prot = (protocol_def *) fl_ent->data;
325     i = proto_get_id_by_filter_name(prot->name);
326     if (i == -1) {
327       /* XXX - complain here? */
328     } else {
329       if (proto_can_toggle_protocol(i))
330         proto_set_decoding(i, FALSE);
331     }
332
333     fl_ent = fl_ent->next;
334   }
335
336 skip:
337   if (global_disabled_protos == NULL)
338     return;
339
340   fl_ent = g_list_first(global_disabled_protos);
341
342   while (fl_ent != NULL) {
343     prot = (protocol_def *) fl_ent->data;
344     i = proto_get_id_by_filter_name(prot->name);
345     if (i == -1) {
346       /* XXX - complain here? */
347     } else {
348       if (proto_can_toggle_protocol(i)) {
349         proto_set_decoding(i, FALSE);
350         proto_set_cant_toggle(i);
351       }
352     }
353
354     fl_ent = fl_ent->next;
355   }
356 }
357
358 /*
359  * Disable a particular protocol by name
360  */
361
362 void
363 proto_disable_proto_by_name(const char *name)
364 {
365     protocol_t *protocol;
366     int proto_id;
367
368     proto_id = proto_get_id_by_filter_name(name);
369     if (proto_id >= 0 ) {
370         protocol = find_protocol_by_id(proto_id);
371         if (proto_is_protocol_enabled(protocol) == TRUE) {
372             if (proto_can_toggle_protocol(proto_id) == TRUE) {
373                 proto_set_decoding(proto_id, FALSE);
374             }
375         }
376     }
377 }
378
379 /*
380  * Write out a list of disabled protocols.
381  *
382  * On success, "*pref_path_return" is set to NULL.
383  * On error, "*pref_path_return" is set to point to the pathname of
384  * the file we tried to read - it should be freed by our caller -
385  * and "*errno_return" is set to the error.
386  */
387 void
388 save_disabled_protos_list(char **pref_path_return, int *errno_return)
389 {
390   gchar       *ff_path, *ff_path_new;
391   FILE        *ff;
392   gint         i;
393   protocol_t  *protocol;
394   void        *cookie;
395
396   *pref_path_return = NULL;     /* assume no error */
397
398   ff_path = get_persconffile_path(PROTOCOLS_FILE_NAME, TRUE);
399
400   /* Write to "XXX.new", and rename if that succeeds.
401      That means we don't trash the file if we fail to write it out
402      completely. */
403   ff_path_new = g_strdup_printf("%s.new", ff_path);
404
405   if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
406     *pref_path_return = ff_path;
407     *errno_return = errno;
408     g_free(ff_path_new);
409     return;
410   }
411
412   /* Iterate over all the protocols */
413
414   for (i = proto_get_first_protocol(&cookie); i != -1;
415        i = proto_get_next_protocol(&cookie)) {
416
417     if (!proto_can_toggle_protocol(i)) {
418       continue;
419     }
420
421     protocol = find_protocol_by_id(i);
422     if (proto_is_protocol_enabled(protocol)) {
423       continue;
424     }
425
426     /* Write out the protocol name. */
427     fprintf(ff, "%s\n", proto_get_protocol_filter_name(i));
428   }
429
430   if (fclose(ff) == EOF) {
431     *pref_path_return = ff_path;
432     *errno_return = errno;
433     ws_unlink(ff_path_new);
434     g_free(ff_path_new);
435     return;
436   }
437
438 #ifdef _WIN32
439   /* ANSI C doesn't say whether "rename()" removes the target if it
440      exists; the Win32 call to rename files doesn't do so, which I
441      infer is the reason why the MSVC++ "rename()" doesn't do so.
442      We must therefore remove the target file first, on Windows.
443
444      XXX - ws_rename() should be ws_stdio_rename() on Windows,
445      and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
446      so it should remove the target if it exists, so this stuff
447      shouldn't be necessary.  Perhaps it dates back to when we were
448      calling rename(), with that being a wrapper around Microsoft's
449      _rename(), which didn't remove the target. */
450   if (ws_remove(ff_path) < 0 && errno != ENOENT) {
451     /* It failed for some reason other than "it's not there"; if
452        it's not there, we don't need to remove it, so we just
453        drive on. */
454     *pref_path_return = ff_path;
455     *errno_return = errno;
456     ws_unlink(ff_path_new);
457     g_free(ff_path_new);
458     return;
459   }
460 #endif
461
462   if (ws_rename(ff_path_new, ff_path) < 0) {
463     *pref_path_return = ff_path;
464     *errno_return = errno;
465     ws_unlink(ff_path_new);
466     g_free(ff_path_new);
467     return;
468   }
469   g_free(ff_path_new);
470   g_free(ff_path);
471 }
472
473 void
474 set_disabled_heur_dissector_list(void)
475 {
476   GList *fl_ent;
477   heur_protocol_def *heur;
478   heur_dtbl_entry_t* h;
479
480   if (disabled_heuristics == NULL)
481     goto skip;
482
483   fl_ent = g_list_first(disabled_heuristics);
484
485   while (fl_ent != NULL) {
486     heur = (heur_protocol_def *) fl_ent->data;
487     h = find_heur_dissector_by_unique_short_name(heur->name);
488     if (h != NULL) {
489       h->enabled = heur->enabled;
490     }
491
492     fl_ent = fl_ent->next;
493   }
494
495 skip:
496   if (global_disabled_heuristics == NULL)
497     return;
498
499   fl_ent = g_list_first(global_disabled_heuristics);
500
501   while (fl_ent != NULL) {
502     heur = (heur_protocol_def *) fl_ent->data;
503
504     h = find_heur_dissector_by_unique_short_name(heur->name);
505     if (h != NULL) {
506       h->enabled = heur->enabled;
507     }
508
509     fl_ent = fl_ent->next;
510   }
511 }
512
513 static int
514 read_disabled_heur_dissector_list_file(const char *ff_path, FILE *ff,
515                                GList **flp)
516 {
517   heur_protocol_def *heur;
518   int         c;
519   char       *heuristic_name;
520   int         heuristic_name_len;
521   int         name_index;
522   gboolean    parse_enabled;
523   gboolean    enabled;
524   int         line = 1;
525
526
527   /* Allocate the protocol name buffer. */
528   heuristic_name_len = INIT_BUF_SIZE;
529   heuristic_name = (char *)g_malloc(heuristic_name_len + 1);
530
531   for (line = 1; ; line++) {
532     /* Lines in a disabled protocol file contain the "filter name" of
533        a protocol to be disabled. */
534
535     /* Skip over leading white space, if any. */
536     while ((c = getc(ff)) != EOF && g_ascii_isspace(c)) {
537       if (c == '\n') {
538         /* Blank line. */
539         continue;
540       }
541     }
542
543     if (c == EOF) {
544       if (ferror(ff))
545         goto error;     /* I/O error */
546       else
547         break;  /* Nothing more to read */
548     }
549     ungetc(c, ff);      /* Unread the non-white-space character. */
550
551     /* Get the name of the protocol. */
552     name_index = 0;
553     enabled = FALSE;
554     parse_enabled = FALSE;
555     for (;;) {
556       c = getc(ff);
557       if (c == EOF)
558         break;  /* End of file, or I/O error */
559       if (g_ascii_isspace(c))
560         break;  /* Trailing white space, or end of line. */
561       if (c == ',') {/* Separator for enable/disable */
562         parse_enabled = TRUE;
563         continue;
564       }
565       if (c == '#')
566         break;  /* Start of comment, running to end of line. */
567       if (parse_enabled) {
568           enabled = ((c == '1') ? TRUE : FALSE);
569           break;
570       }
571       /* Add this character to the protocol name string. */
572       if (name_index >= heuristic_name_len) {
573         /* protocol name buffer isn't long enough; double its length. */
574         heuristic_name_len *= 2;
575         heuristic_name = (char *)g_realloc(heuristic_name, heuristic_name_len + 1);
576       }
577       heuristic_name[name_index] = c;
578       name_index++;
579     }
580
581     if (g_ascii_isspace(c) && c != '\n') {
582       /* Skip over trailing white space. */
583       while ((c = getc(ff)) != EOF && c != '\n' && g_ascii_isspace(c))
584         ;
585       if (c != EOF && c != '\n' && c != '#') {
586         /* Non-white-space after the protocol name; warn about it,
587            in case we come up with a reason to use it. */
588         g_warning("'%s' line %d has extra stuff after the protocol name.",
589                   ff_path, line);
590       }
591     }
592     if (c != EOF && c != '\n') {
593       /* Skip to end of line. */
594       while ((c = getc(ff)) != EOF && c != '\n')
595         ;
596     }
597
598     if (c == EOF) {
599       if (ferror(ff))
600         goto error;     /* I/O error */
601       else {
602         /* EOF, not error; no newline seen before EOF */
603         g_warning("'%s' line %d doesn't have a newline.", ff_path,
604                   line);
605       }
606       break;    /* nothing more to read */
607     }
608
609     /* Null-terminate the protocol name. */
610     if (name_index >= heuristic_name_len) {
611       /* protocol name buffer isn't long enough; double its length. */
612       heuristic_name_len *= 2;
613       heuristic_name = (char *)g_realloc(heuristic_name, heuristic_name_len + 1);
614     }
615     heuristic_name[name_index] = '\0';
616
617     /* Add the new protocol to the list of disabled protocols */
618     heur         = (heur_protocol_def *) g_malloc(sizeof(heur_protocol_def));
619     heur->name   = g_strdup(heuristic_name);
620     heur->enabled = enabled;
621     *flp = g_list_append(*flp, heur);
622   }
623   g_free(heuristic_name);
624   return 0;
625
626 error:
627   g_free(heuristic_name);
628   return errno;
629 }
630
631 void
632 read_disabled_heur_dissector_list(char **gpath_return, int *gopen_errno_return,
633                           int *gread_errno_return,
634                           char **path_return, int *open_errno_return,
635                           int *read_errno_return)
636 {
637   int         err;
638   char       *gff_path, *ff_path;
639   FILE       *ff;
640
641   /* Construct the pathname of the global disabled heuristic dissectors file. */
642   gff_path = get_datafile_path(HEURISTICS_FILE_NAME);
643
644   /* If we already have a list of protocols, discard it. */
645   heur_discard_existing_list(&global_disabled_heuristics);
646
647   /* Read the global disabled protocols file, if it exists. */
648   *gpath_return = NULL;
649   if ((ff = ws_fopen(gff_path, "r")) != NULL) {
650     /* We succeeded in opening it; read it. */
651     err = read_disabled_heur_dissector_list_file(gff_path, ff,
652                                          &global_disabled_heuristics);
653     if (err != 0) {
654       /* We had an error reading the file; return the errno and the
655          pathname, so our caller can report the error. */
656       *gopen_errno_return = 0;
657       *gread_errno_return = err;
658       *gpath_return = gff_path;
659     } else
660       g_free(gff_path);
661     fclose(ff);
662   } else {
663     /* We failed to open it.  If we failed for some reason other than
664        "it doesn't exist", return the errno and the pathname, so our
665        caller can report the error. */
666     if (errno != ENOENT) {
667       *gopen_errno_return = errno;
668       *gread_errno_return = 0;
669       *gpath_return = gff_path;
670     } else
671       g_free(gff_path);
672   }
673
674   /* Construct the pathname of the user's disabled protocols file. */
675   ff_path = get_persconffile_path(HEURISTICS_FILE_NAME, TRUE);
676
677   /* If we already have a list of protocols, discard it. */
678   heur_discard_existing_list (&disabled_heuristics);
679
680   /* Read the user's disabled protocols file, if it exists. */
681   *path_return = NULL;
682   if ((ff = ws_fopen(ff_path, "r")) != NULL) {
683     /* We succeeded in opening it; read it. */
684     err = read_disabled_heur_dissector_list_file(ff_path, ff, &disabled_heuristics);
685     if (err != 0) {
686       /* We had an error reading the file; return the errno and the
687          pathname, so our caller can report the error. */
688       *open_errno_return = 0;
689       *read_errno_return = err;
690       *path_return = ff_path;
691     } else
692       g_free(ff_path);
693     fclose(ff);
694   } else {
695     /* We failed to open it.  If we failed for some reason other than
696        "it doesn't exist", return the errno and the pathname, so our
697        caller can report the error. */
698     if (errno != ENOENT) {
699       *open_errno_return = errno;
700       *read_errno_return = 0;
701       *path_return = ff_path;
702     } else
703       g_free(ff_path);
704   }
705 }
706
707 static gint
708 heur_compare(gconstpointer a, gconstpointer b)
709 {
710   return strcmp(((heur_dtbl_entry_t*)a)->short_name,
711         ((heur_dtbl_entry_t*)b)->short_name);
712 }
713
714 static void
715 write_heur_dissector(gpointer data, gpointer user_data)
716 {
717   heur_dtbl_entry_t* dtbl_entry = (heur_dtbl_entry_t*)data;
718   FILE *ff = (FILE*)user_data;
719
720   /* Write out the heuristic short name and its enabled state */
721   fprintf(ff, "%s,%d\n", dtbl_entry->short_name, dtbl_entry->enabled ? 1 : 0);
722 }
723
724 static void
725 sort_dissector_table_entries(const char *table_name _U_,
726     heur_dtbl_entry_t *dtbl_entry, gpointer user_data)
727 {
728   GSList **list = (GSList**)user_data;
729   *list = g_slist_insert_sorted(*list, dtbl_entry, heur_compare);
730 }
731
732 static void
733 sort_heur_dissector_tables(const char *table_name, heur_dissector_list_t *list, gpointer w)
734 {
735   if (list) {
736     heur_dissector_table_foreach(table_name, sort_dissector_table_entries, w);
737   }
738 }
739
740 WS_DLL_PUBLIC void
741 save_disabled_heur_dissector_list(char **pref_path_return, int *errno_return)
742 {
743   gchar       *ff_path, *ff_path_new;
744   GSList      *sorted_heur_list = NULL;
745   FILE        *ff;
746
747   *pref_path_return = NULL;     /* assume no error */
748
749   ff_path = get_persconffile_path(HEURISTICS_FILE_NAME, TRUE);
750
751   /* Write to "XXX.new", and rename if that succeeds.
752      That means we don't trash the file if we fail to write it out
753      completely. */
754   ff_path_new = g_strdup_printf("%s.new", ff_path);
755
756   if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
757     *pref_path_return = ff_path;
758     *errno_return = errno;
759     g_free(ff_path_new);
760     return;
761   }
762
763   /* Iterate over all the heuristic dissectors to sort them in alphabetical order by short name */
764   dissector_all_heur_tables_foreach_table(sort_heur_dissector_tables, &sorted_heur_list, NULL);
765
766   /* Write the list */
767   g_slist_foreach(sorted_heur_list, write_heur_dissector, ff);
768   g_slist_free(sorted_heur_list);
769
770   if (fclose(ff) == EOF) {
771     *pref_path_return = ff_path;
772     *errno_return = errno;
773     ws_unlink(ff_path_new);
774     g_free(ff_path_new);
775     return;
776   }
777
778 #ifdef _WIN32
779   /* ANSI C doesn't say whether "rename()" removes the target if it
780      exists; the Win32 call to rename files doesn't do so, which I
781      infer is the reason why the MSVC++ "rename()" doesn't do so.
782      We must therefore remove the target file first, on Windows.
783
784      XXX - ws_rename() should be ws_stdio_rename() on Windows,
785      and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
786      so it should remove the target if it exists, so this stuff
787      shouldn't be necessary.  Perhaps it dates back to when we were
788      calling rename(), with that being a wrapper around Microsoft's
789      _rename(), which didn't remove the target. */
790   if (ws_remove(ff_path) < 0 && errno != ENOENT) {
791     /* It failed for some reason other than "it's not there"; if
792        it's not there, we don't need to remove it, so we just
793        drive on. */
794     *pref_path_return = ff_path;
795     *errno_return = errno;
796     ws_unlink(ff_path_new);
797     g_free(ff_path_new);
798     return;
799   }
800 #endif
801
802   if (ws_rename(ff_path_new, ff_path) < 0) {
803     *pref_path_return = ff_path;
804     *errno_return = errno;
805     ws_unlink(ff_path_new);
806     g_free(ff_path_new);
807     return;
808   }
809   g_free(ff_path_new);
810   g_free(ff_path);
811 }
812
813 void
814 proto_enable_heuristic_by_name(const char *name, gboolean enable)
815 {
816   heur_dtbl_entry_t* heur = find_heur_dissector_by_unique_short_name(name);
817   if (heur != NULL) {
818       heur->enabled = enable;
819   }
820 }
821
822 /*
823  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
824  *
825  * Local Variables:
826  * c-basic-offset: 2
827  * tab-width: 8
828  * indent-tabs-mode: nil
829  * End:
830  *
831  * ex: set shiftwidth=2 tabstop=8 expandtab:
832  * :indentSize=2:tabSize=8:noTabs=true:
833  */