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