| @@ -1,26 +1,26 @@ | | | @@ -1,26 +1,26 @@ |
1 | /* $NetBSD: zic.c,v 1.63 2016/10/07 15:29:42 christos Exp $ */ | | 1 | /* $NetBSD: zic.c,v 1.64 2016/10/07 19:47:16 kre Exp $ */ |
2 | /* | | 2 | /* |
3 | ** This file is in the public domain, so clarified as of | | 3 | ** This file is in the public domain, so clarified as of |
4 | ** 2006-07-17 by Arthur David Olson. | | 4 | ** 2006-07-17 by Arthur David Olson. |
5 | */ | | 5 | */ |
6 | | | 6 | |
7 | #if HAVE_NBTOOL_CONFIG_H | | 7 | #if HAVE_NBTOOL_CONFIG_H |
8 | #include "nbtool_config.h" | | 8 | #include "nbtool_config.h" |
9 | #endif | | 9 | #endif |
10 | | | 10 | |
11 | #include <sys/cdefs.h> | | 11 | #include <sys/cdefs.h> |
12 | #ifndef lint | | 12 | #ifndef lint |
13 | __RCSID("$NetBSD: zic.c,v 1.63 2016/10/07 15:29:42 christos Exp $"); | | 13 | __RCSID("$NetBSD: zic.c,v 1.64 2016/10/07 19:47:16 kre Exp $"); |
14 | #endif /* !defined lint */ | | 14 | #endif /* !defined lint */ |
15 | | | 15 | |
16 | #include "private.h" | | 16 | #include "private.h" |
17 | #include "locale.h" | | 17 | #include "locale.h" |
18 | #include "tzfile.h" | | 18 | #include "tzfile.h" |
19 | | | 19 | |
20 | #include <stdarg.h> | | 20 | #include <stdarg.h> |
21 | #include <unistd.h> | | 21 | #include <unistd.h> |
22 | #include <util.h> | | 22 | #include <util.h> |
23 | | | 23 | |
24 | #define ZIC_VERSION_PRE_2013 '2' | | 24 | #define ZIC_VERSION_PRE_2013 '2' |
25 | #define ZIC_VERSION '3' | | 25 | #define ZIC_VERSION '3' |
26 | | | 26 | |
| @@ -766,26 +766,64 @@ namecheck(const char *name) | | | @@ -766,26 +766,64 @@ namecheck(const char *name) |
766 | ? _("file name '%s' contains byte '%c'") | | 766 | ? _("file name '%s' contains byte '%c'") |
767 | : _("file name '%s' contains byte '\\%o'")), | | 767 | : _("file name '%s' contains byte '\\%o'")), |
768 | name, c); | | 768 | name, c); |
769 | } | | 769 | } |
770 | if (c == '/') { | | 770 | if (c == '/') { |
771 | if (!componentcheck(name, component, cp)) | | 771 | if (!componentcheck(name, component, cp)) |
772 | return false; | | 772 | return false; |
773 | component = cp + 1; | | 773 | component = cp + 1; |
774 | } | | 774 | } |
775 | } | | 775 | } |
776 | return componentcheck(name, component, cp); | | 776 | return componentcheck(name, component, cp); |
777 | } | | 777 | } |
778 | | | 778 | |
| | | 779 | /* Create symlink contents suitable for symlinking FROM to TO, as a |
| | | 780 | freshly allocated string. FROM should be a relative file name, and |
| | | 781 | is relative to the global variable DIRECTORY. TO can be either |
| | | 782 | relative or absolute. */ |
| | | 783 | static char * |
| | | 784 | relname(char const *from, char const *to) |
| | | 785 | { |
| | | 786 | size_t i, taillen, dotdotetcsize; |
| | | 787 | size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX; |
| | | 788 | char const *f = from; |
| | | 789 | char *result = NULL; |
| | | 790 | if (*to == '/') { |
| | | 791 | /* Make F absolute too. */ |
| | | 792 | size_t len = strlen(directory); |
| | | 793 | bool needslash = len && directory[len - 1] != '/'; |
| | | 794 | linksize = len + needslash + strlen(from) + 1; |
| | | 795 | f = result = emalloc(linksize); |
| | | 796 | strcpy(result, directory); |
| | | 797 | result[len] = '/'; |
| | | 798 | strcpy(result + len + needslash, from); |
| | | 799 | } |
| | | 800 | for (i = 0; f[i] && f[i] == to[i]; i++) |
| | | 801 | if (f[i] == '/') |
| | | 802 | dir_len = i + 1; |
| | | 803 | for (; f[i]; i++) |
| | | 804 | dotdots += f[i] == '/' && f[i - 1] != '/'; |
| | | 805 | taillen = i - dir_len; |
| | | 806 | dotdotetcsize = 3 * dotdots + taillen + 1; |
| | | 807 | if (dotdotetcsize <= linksize) { |
| | | 808 | if (!result) |
| | | 809 | result = emalloc(dotdotetcsize); |
| | | 810 | for (i = 0; i < dotdots; i++) |
| | | 811 | memcpy(result + 3 * i, "../", 3); |
| | | 812 | memmove(result + 3 * dotdots, f + dir_len, taillen + 1); |
| | | 813 | } |
| | | 814 | return result; |
| | | 815 | } |
| | | 816 | |
779 | static void | | 817 | static void |
780 | dolink(char const *fromfield, char const *tofield, bool staysymlink) | | 818 | dolink(char const *fromfield, char const *tofield, bool staysymlink) |
781 | { | | 819 | { |
782 | int fromisdir; | | 820 | int fromisdir; |
783 | bool todirs_made = false; | | 821 | bool todirs_made = false; |
784 | int link_errno; | | 822 | int link_errno; |
785 | | | 823 | |
786 | /* | | 824 | /* |
787 | ** We get to be careful here since | | 825 | ** We get to be careful here since |
788 | ** there's a fair chance of root running us. | | 826 | ** there's a fair chance of root running us. |
789 | */ | | 827 | */ |
790 | fromisdir = itsdir(fromfield); | | 828 | fromisdir = itsdir(fromfield); |
791 | if (fromisdir) { | | 829 | if (fromisdir) { |
| @@ -802,50 +840,35 @@ dolink(char const *fromfield, char const | | | @@ -802,50 +840,35 @@ dolink(char const *fromfield, char const |
802 | char const *e = strerror(errno); | | 840 | char const *e = strerror(errno); |
803 | fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), | | 841 | fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), |
804 | progname, directory, tofield, e); | | 842 | progname, directory, tofield, e); |
805 | exit(EXIT_FAILURE); | | 843 | exit(EXIT_FAILURE); |
806 | } | | 844 | } |
807 | link_errno = (staysymlink ? ENOTSUP | | 845 | link_errno = (staysymlink ? ENOTSUP |
808 | : link(fromfield, tofield) == 0 ? 0 : errno); | | 846 | : link(fromfield, tofield) == 0 ? 0 : errno); |
809 | if (link_errno == ENOENT && !todirs_made) { | | 847 | if (link_errno == ENOENT && !todirs_made) { |
810 | mkdirs(tofield, true); | | 848 | mkdirs(tofield, true); |
811 | todirs_made = true; | | 849 | todirs_made = true; |
812 | link_errno = link(fromfield, tofield) == 0 ? 0 : errno; | | 850 | link_errno = link(fromfield, tofield) == 0 ? 0 : errno; |
813 | } | | 851 | } |
814 | if (link_errno != 0) { | | 852 | if (link_errno != 0) { |
815 | const char *s = fromfield; | | 853 | bool absolute = *fromfield == '/'; |
816 | const char *t; | | 854 | char *linkalloc = absolute ? NULL : relname(fromfield, tofield); |
817 | char *p; | | 855 | char const *contents = absolute ? fromfield : linkalloc; |
818 | size_t dotdots = 0; | | 856 | int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno; |
819 | char *symlinkcontents; | | | |
820 | int symlink_errno; | | | |
821 | | | | |
822 | do | | | |
823 | t = s; | | | |
824 | while ((s = strchr(s, '/')) | | | |
825 | && strncmp(fromfield, tofield, ++s - fromfield) == 0); | | | |
826 | | | | |
827 | for (s = tofield + (t - fromfield); *s; s++) | | | |
828 | dotdots += *s == '/'; | | | |
829 | symlinkcontents = emalloc(3 * dotdots + strlen(t) + 1); | | | |
830 | for (p = symlinkcontents; dotdots-- != 0; p += 3) | | | |
831 | memcpy(p, "../", 3); | | | |
832 | strcpy(p, t); | | | |
833 | symlink_errno = symlink(symlinkcontents, tofield) == 0 ? 0 : errno; | | | |
834 | if (symlink_errno == ENOENT && !todirs_made) { | | 857 | if (symlink_errno == ENOENT && !todirs_made) { |
835 | mkdirs(tofield, true); | | 858 | mkdirs(tofield, true); |
836 | symlink_errno = symlink(symlinkcontents, tofield) == 0 ? 0 : errno; | | 859 | symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno; |
837 | } | | 860 | } |
838 | free(symlinkcontents); | | 861 | free(linkalloc); |
839 | if (symlink_errno == 0) { | | 862 | if (symlink_errno == 0) { |
840 | if (link_errno != ENOTSUP) | | 863 | if (link_errno != ENOTSUP) |
841 | warning(_("symbolic link used because hard link failed: %s"), | | 864 | warning(_("symbolic link used because hard link failed: %s"), |
842 | strerror(link_errno)); | | 865 | strerror(link_errno)); |
843 | } else { | | 866 | } else { |
844 | FILE *fp, *tp; | | 867 | FILE *fp, *tp; |
845 | int c; | | 868 | int c; |
846 | fp = fopen(fromfield, "rb"); | | 869 | fp = fopen(fromfield, "rb"); |
847 | if (!fp) { | | 870 | if (!fp) { |
848 | char const *e = strerror(errno); | | 871 | char const *e = strerror(errno); |
849 | fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), | | 872 | fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), |
850 | progname, directory, fromfield, e); | | 873 | progname, directory, fromfield, e); |
851 | exit(EXIT_FAILURE); | | 874 | exit(EXIT_FAILURE); |