Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / fs / archelp.c
blobc85cbfac29ebbdce8938e6dbb62930cb9f3ef00b
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2007,2008,2009,2013 Free Software Foundation, Inc.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/archelp.h>
20 #include <grub/err.h>
21 #include <grub/fs.h>
22 #include <grub/disk.h>
23 #include <grub/dl.h>
25 GRUB_MOD_LICENSE ("GPLv3+");
27 static inline void
28 canonicalize (char *name)
30 char *iptr, *optr;
31 for (iptr = name, optr = name; *iptr; )
33 while (*iptr == '/')
34 iptr++;
35 if (iptr[0] == '.' && (iptr[1] == '/' || iptr[1] == 0))
37 iptr += 2;
38 continue;
40 if (iptr[0] == '.' && iptr[1] == '.' && (iptr[2] == '/' || iptr[2] == 0))
42 iptr += 3;
43 if (optr == name)
44 continue;
45 for (optr -= 2; optr >= name && *optr != '/'; optr--);
46 optr++;
47 continue;
49 while (*iptr && *iptr != '/')
50 *optr++ = *iptr++;
51 if (*iptr)
52 *optr++ = *iptr++;
54 *optr = 0;
57 static grub_err_t
58 handle_symlink (struct grub_archelp_data *data,
59 struct grub_archelp_ops *arcops,
60 const char *fn, char **name,
61 grub_uint32_t mode, int *restart)
63 grub_size_t flen;
64 char *target;
65 char *ptr;
66 char *lastslash;
67 grub_size_t prefixlen;
68 char *rest;
69 char *linktarget;
70 grub_size_t linktarget_len;
72 *restart = 0;
74 if ((mode & GRUB_ARCHELP_ATTR_TYPE) != GRUB_ARCHELP_ATTR_LNK
75 || !arcops->get_link_target)
76 return GRUB_ERR_NONE;
77 flen = grub_strlen (fn);
78 if (grub_memcmp (*name, fn, flen) != 0
79 || ((*name)[flen] != 0 && (*name)[flen] != '/'))
80 return GRUB_ERR_NONE;
81 rest = *name + flen;
82 lastslash = rest;
83 if (*rest)
84 rest++;
85 while (lastslash >= *name && *lastslash != '/')
86 lastslash--;
87 if (lastslash >= *name)
88 prefixlen = lastslash - *name;
89 else
90 prefixlen = 0;
92 if (prefixlen)
93 prefixlen++;
95 linktarget = arcops->get_link_target (data);
96 if (!linktarget)
97 return grub_errno;
98 if (linktarget[0] == '\0')
99 return GRUB_ERR_NONE;
100 linktarget_len = grub_strlen (linktarget);
101 target = grub_malloc (linktarget_len + grub_strlen (*name) + 2);
102 if (!target)
103 return grub_errno;
105 grub_strcpy (target + prefixlen, linktarget);
106 grub_free (linktarget);
107 if (target[prefixlen] == '/')
109 ptr = grub_stpcpy (target, target + prefixlen);
110 ptr = grub_stpcpy (ptr, rest);
111 *ptr = 0;
112 grub_dprintf ("archelp", "symlink redirected %s to %s\n",
113 *name, target);
114 grub_free (*name);
116 canonicalize (target);
117 *name = target;
118 *restart = 1;
119 return GRUB_ERR_NONE;
121 if (prefixlen)
123 grub_memcpy (target, *name, prefixlen);
124 target[prefixlen-1] = '/';
126 grub_strcpy (target + prefixlen + linktarget_len, rest);
127 grub_dprintf ("archelp", "symlink redirected %s to %s\n",
128 *name, target);
129 grub_free (*name);
130 canonicalize (target);
131 *name = target;
132 *restart = 1;
133 return GRUB_ERR_NONE;
136 grub_err_t
137 grub_archelp_dir (struct grub_archelp_data *data,
138 struct grub_archelp_ops *arcops,
139 const char *path_in,
140 grub_fs_dir_hook_t hook, void *hook_data)
142 char *prev, *name, *path, *ptr;
143 grub_size_t len;
144 int symlinknest = 0;
146 path = grub_strdup (path_in + 1);
147 if (!path)
148 return grub_errno;
149 canonicalize (path);
150 for (ptr = path + grub_strlen (path) - 1; ptr >= path && *ptr == '/'; ptr--)
151 *ptr = 0;
153 prev = 0;
155 len = grub_strlen (path);
156 while (1)
158 grub_int32_t mtime;
159 grub_uint32_t mode;
160 grub_err_t err;
162 if (arcops->find_file (data, &name, &mtime, &mode))
163 goto fail;
165 if (mode == GRUB_ARCHELP_ATTR_END)
166 break;
168 canonicalize (name);
170 if (grub_memcmp (path, name, len) == 0
171 && (name[len] == 0 || name[len] == '/' || len == 0))
173 char *p, *n;
175 n = name + len;
176 while (*n == '/')
177 n++;
179 p = grub_strchr (n, '/');
180 if (p)
181 *p = 0;
183 if (((!prev) || (grub_strcmp (prev, name) != 0)) && *n != 0)
185 struct grub_dirhook_info info;
186 grub_memset (&info, 0, sizeof (info));
187 info.dir = (p != NULL) || ((mode & GRUB_ARCHELP_ATTR_TYPE)
188 == GRUB_ARCHELP_ATTR_DIR);
189 if (!(mode & GRUB_ARCHELP_ATTR_NOTIME))
191 info.mtime = mtime;
192 info.mtimeset = 1;
194 if (hook (n, &info, hook_data))
196 grub_free (name);
197 goto fail;
199 grub_free (prev);
200 prev = name;
202 else
204 int restart = 0;
205 err = handle_symlink (data, arcops, name,
206 &path, mode, &restart);
207 grub_free (name);
208 if (err)
209 goto fail;
210 if (restart)
212 len = grub_strlen (path);
213 if (++symlinknest == 8)
215 grub_error (GRUB_ERR_SYMLINK_LOOP,
216 N_("too deep nesting of symlinks"));
217 goto fail;
219 arcops->rewind (data);
223 else
224 grub_free (name);
227 fail:
229 grub_free (path);
230 grub_free (prev);
232 return grub_errno;
235 grub_err_t
236 grub_archelp_open (struct grub_archelp_data *data,
237 struct grub_archelp_ops *arcops,
238 const char *name_in)
240 char *fn;
241 char *name = grub_strdup (name_in + 1);
242 int symlinknest = 0;
244 if (!name)
245 return grub_errno;
247 canonicalize (name);
249 while (1)
251 grub_uint32_t mode;
252 int restart;
254 if (arcops->find_file (data, &fn, NULL, &mode))
255 goto fail;
257 if (mode == GRUB_ARCHELP_ATTR_END)
259 grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name_in);
260 break;
263 canonicalize (fn);
265 if (handle_symlink (data, arcops, fn, &name, mode, &restart))
267 grub_free (fn);
268 goto fail;
271 if (restart)
273 arcops->rewind (data);
274 if (++symlinknest == 8)
276 grub_error (GRUB_ERR_SYMLINK_LOOP,
277 N_("too deep nesting of symlinks"));
278 goto fail;
280 goto no_match;
283 if (grub_strcmp (name, fn) != 0)
284 goto no_match;
286 grub_free (fn);
287 grub_free (name);
289 return GRUB_ERR_NONE;
291 no_match:
293 grub_free (fn);
296 fail:
297 grub_free (name);
299 return grub_errno;