1 /*
2 Copyright (C) 2009 Hans Beckerus (hans.beckerus#AT#gmail.com)
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 This program take use of the freeware "Unrar C++ Library" (libunrar)
18 by Alexander Roshal and some extensions to it.
19
20 Unrar source may be used in any software to handle RAR archives
21 without limitations free of charge, but cannot be used to re-create
22 the RAR compression algorithm, which is proprietary. Distribution
23 of modified Unrar source in separate form or as a part of other
24 software is permitted, provided that it is clearly stated in
25 the documentation and source comments that the code may not be used
26 to develop a RAR (WinRAR) compatible archiver.
27 */
28
29 #include <platform.h>
30 #include <libgen.h>
31 #include <string.h>
32
33 #ifndef HAVE_MEMRCHR
34 /*!
35 *****************************************************************************
36 * Fallback function if memrchr(3) GNU extension is not available.
37 * Somewhat less optimized but will do the job pretty well.
38 ****************************************************************************/
memrchr(const void * s,int c_in,size_t n)39 static inline void *memrchr(const void *s, int c_in, size_t n)
40 {
41 const unsigned char *p;
42 unsigned char c;
43
44 c = (unsigned char)c_in;
45 p = (const unsigned char *)s + n;
46 while (n-- > 0)
47 if (*--p == c)
48 return (void *)p;
49 return 0;
50 }
51 #endif
52
53 #ifndef HAVE_GNU_DIRNAME
54 /*!
55 *****************************************************************************
56 * dirname - return directory part of PATH.
57 * Copyright (C) 1996-2019 Free Software Foundation, Inc.
58 *
59 * Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
60 * The GNU C Library is free software; you can redistribute it and/or
61 * modify it under the terms of the GNU Lesser General Public
62 * License as published by the Free Software Foundation; either
63 * version 2.1 of the License, or (at your option) any later version.
64 * The GNU C Library is distributed in the hope that it will be useful,
65 * but WITHOUT ANY WARRANTY; without even the implied warranty of
66 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
67 * Lesser General Public License for more details.
68 * You should have received a copy of the GNU Lesser General Public
69 * License along with the GNU C Library; if not, see
70 * <http://www.gnu.org/licenses/>.
71 *
72 * This is more or less a direct copy of the function from the GNU C Library.
73 * It has been renamed to not clash with the existing library function and
74 * also re-formatted to align with the rest of the design.
75 '
76 * The purpose of this function is to avoid the dilemma with dirname(3)'s
77 * many different implementations. Some are thread safe some are not.
78 * Some modify its argument, some do not. If we are going to use dirname(3)
79 * we have to treat it as being both non thread safe and input modifying.
80 * At which point it is much easier to use something else that is known to
81 * implement the same semantics across all platforms.
82 *
83 ****************************************************************************/
__gnu_dirname(char * path)84 char *__gnu_dirname(char *path)
85 {
86 static const char dot[] = ".";
87 char *last_slash;
88
89 /* Find last '/'. */
90 last_slash = path != NULL ? strrchr(path, '/') : NULL;
91 if (last_slash != NULL && last_slash != path && last_slash[1] == '\0') {
92 /* Determine whether all remaining characters are slashes. */
93 char *runp;
94 for (runp = last_slash; runp != path; --runp)
95 if (runp[-1] != '/')
96 break;
97 /* The '/' is the last character, we have to look further. */
98 if (runp != path)
99 last_slash = memrchr(path, '/', runp - path);
100 }
101 if (last_slash != NULL) {
102 /* Determine whether all remaining characters are slashes. */
103 char *runp;
104 for (runp = last_slash; runp != path; --runp)
105 if (runp[-1] != '/')
106 break;
107 /* Terminate the path. */
108 if (runp == path) {
109 /* The last slash is the first character in the string.
110 We have to return "/". As a special case we have to
111 return "//" if there are exactly two slashes at the
112 beginning of the string. See XBD 4.10 Path Name
113 Resolution for more information. */
114 if (last_slash == path + 1)
115 ++last_slash;
116 else
117 last_slash = path + 1;
118 } else {
119 last_slash = runp;
120 }
121 last_slash[0] = '\0';
122 } else {
123 /* This assignment is ill-designed but the XPG specs require to
124 return a string containing "." in any case no directory part is
125 found and so a static and constant string is required. */
126 path = (char *)dot;
127 }
128
129 return path;
130 }
131 #endif
132