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>
22 #include <grub/disk.h>
25 GRUB_MOD_LICENSE ("GPLv3+");
28 canonicalize (char *name
)
31 for (iptr
= name
, optr
= name
; *iptr
; )
35 if (iptr
[0] == '.' && (iptr
[1] == '/' || iptr
[1] == 0))
40 if (iptr
[0] == '.' && iptr
[1] == '.' && (iptr
[2] == '/' || iptr
[2] == 0))
45 for (optr
-= 2; optr
>= name
&& *optr
!= '/'; optr
--);
49 while (*iptr
&& *iptr
!= '/')
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
)
67 grub_size_t prefixlen
;
70 grub_size_t linktarget_len
;
74 if ((mode
& GRUB_ARCHELP_ATTR_TYPE
) != GRUB_ARCHELP_ATTR_LNK
75 || !arcops
->get_link_target
)
77 flen
= grub_strlen (fn
);
78 if (grub_memcmp (*name
, fn
, flen
) != 0
79 || ((*name
)[flen
] != 0 && (*name
)[flen
] != '/'))
85 while (lastslash
>= *name
&& *lastslash
!= '/')
87 if (lastslash
>= *name
)
88 prefixlen
= lastslash
- *name
;
95 linktarget
= arcops
->get_link_target (data
);
98 if (linktarget
[0] == '\0')
100 linktarget_len
= grub_strlen (linktarget
);
101 target
= grub_malloc (linktarget_len
+ grub_strlen (*name
) + 2);
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
);
112 grub_dprintf ("archelp", "symlink redirected %s to %s\n",
116 canonicalize (target
);
119 return GRUB_ERR_NONE
;
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",
130 canonicalize (target
);
133 return GRUB_ERR_NONE
;
137 grub_archelp_dir (struct grub_archelp_data
*data
,
138 struct grub_archelp_ops
*arcops
,
140 grub_fs_dir_hook_t hook
, void *hook_data
)
142 char *prev
, *name
, *path
, *ptr
;
146 path
= grub_strdup (path_in
+ 1);
150 for (ptr
= path
+ grub_strlen (path
) - 1; ptr
>= path
&& *ptr
== '/'; ptr
--)
155 len
= grub_strlen (path
);
162 if (arcops
->find_file (data
, &name
, &mtime
, &mode
))
165 if (mode
== GRUB_ARCHELP_ATTR_END
)
170 if (grub_memcmp (path
, name
, len
) == 0
171 && (name
[len
] == 0 || name
[len
] == '/' || len
== 0))
179 p
= grub_strchr (n
, '/');
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
))
194 if (hook (n
, &info
, hook_data
))
205 err
= handle_symlink (data
, arcops
, name
,
206 &path
, mode
, &restart
);
212 len
= grub_strlen (path
);
213 if (++symlinknest
== 8)
215 grub_error (GRUB_ERR_SYMLINK_LOOP
,
216 N_("too deep nesting of symlinks"));
219 arcops
->rewind (data
);
236 grub_archelp_open (struct grub_archelp_data
*data
,
237 struct grub_archelp_ops
*arcops
,
241 char *name
= grub_strdup (name_in
+ 1);
254 if (arcops
->find_file (data
, &fn
, NULL
, &mode
))
257 if (mode
== GRUB_ARCHELP_ATTR_END
)
259 grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), name_in
);
265 if (handle_symlink (data
, arcops
, fn
, &name
, mode
, &restart
))
273 arcops
->rewind (data
);
274 if (++symlinknest
== 8)
276 grub_error (GRUB_ERR_SYMLINK_LOOP
,
277 N_("too deep nesting of symlinks"));
283 if (grub_strcmp (name
, fn
) != 0)
289 return GRUB_ERR_NONE
;