diff options
Diffstat (limited to 'lib/string.c')
-rw-r--r-- | lib/string.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/lib/string.c b/lib/string.c index 13d1e84ddb80..8dbb7b1eab50 100644 --- a/lib/string.c +++ b/lib/string.c | |||
@@ -27,6 +27,10 @@ | |||
27 | #include <linux/bug.h> | 27 | #include <linux/bug.h> |
28 | #include <linux/errno.h> | 28 | #include <linux/errno.h> |
29 | 29 | ||
30 | #include <asm/byteorder.h> | ||
31 | #include <asm/word-at-a-time.h> | ||
32 | #include <asm/page.h> | ||
33 | |||
30 | #ifndef __HAVE_ARCH_STRNCASECMP | 34 | #ifndef __HAVE_ARCH_STRNCASECMP |
31 | /** | 35 | /** |
32 | * strncasecmp - Case insensitive, length-limited string comparison | 36 | * strncasecmp - Case insensitive, length-limited string comparison |
@@ -146,6 +150,90 @@ size_t strlcpy(char *dest, const char *src, size_t size) | |||
146 | EXPORT_SYMBOL(strlcpy); | 150 | EXPORT_SYMBOL(strlcpy); |
147 | #endif | 151 | #endif |
148 | 152 | ||
153 | #ifndef __HAVE_ARCH_STRSCPY | ||
154 | /** | ||
155 | * strscpy - Copy a C-string into a sized buffer | ||
156 | * @dest: Where to copy the string to | ||
157 | * @src: Where to copy the string from | ||
158 | * @count: Size of destination buffer | ||
159 | * | ||
160 | * Copy the string, or as much of it as fits, into the dest buffer. | ||
161 | * The routine returns the number of characters copied (not including | ||
162 | * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough. | ||
163 | * The behavior is undefined if the string buffers overlap. | ||
164 | * The destination buffer is always NUL terminated, unless it's zero-sized. | ||
165 | * | ||
166 | * Preferred to strlcpy() since the API doesn't require reading memory | ||
167 | * from the src string beyond the specified "count" bytes, and since | ||
168 | * the return value is easier to error-check than strlcpy()'s. | ||
169 | * In addition, the implementation is robust to the string changing out | ||
170 | * from underneath it, unlike the current strlcpy() implementation. | ||
171 | * | ||
172 | * Preferred to strncpy() since it always returns a valid string, and | ||
173 | * doesn't unnecessarily force the tail of the destination buffer to be | ||
174 | * zeroed. If the zeroing is desired, it's likely cleaner to use strscpy() | ||
175 | * with an overflow test, then just memset() the tail of the dest buffer. | ||
176 | */ | ||
177 | ssize_t strscpy(char *dest, const char *src, size_t count) | ||
178 | { | ||
179 | const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; | ||
180 | size_t max = count; | ||
181 | long res = 0; | ||
182 | |||
183 | if (count == 0) | ||
184 | return -E2BIG; | ||
185 | |||
186 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | ||
187 | /* | ||
188 | * If src is unaligned, don't cross a page boundary, | ||
189 | * since we don't know if the next page is mapped. | ||
190 | */ | ||
191 | if ((long)src & (sizeof(long) - 1)) { | ||
192 | size_t limit = PAGE_SIZE - ((long)src & (PAGE_SIZE - 1)); | ||
193 | if (limit < max) | ||
194 | max = limit; | ||
195 | } | ||
196 | #else | ||
197 | /* If src or dest is unaligned, don't do word-at-a-time. */ | ||
198 | if (((long) dest | (long) src) & (sizeof(long) - 1)) | ||
199 | max = 0; | ||
200 | #endif | ||
201 | |||
202 | while (max >= sizeof(unsigned long)) { | ||
203 | unsigned long c, data; | ||
204 | |||
205 | c = *(unsigned long *)(src+res); | ||
206 | *(unsigned long *)(dest+res) = c; | ||
207 | if (has_zero(c, &data, &constants)) { | ||
208 | data = prep_zero_mask(c, data, &constants); | ||
209 | data = create_zero_mask(data); | ||
210 | return res + find_zero(data); | ||
211 | } | ||
212 | res += sizeof(unsigned long); | ||
213 | count -= sizeof(unsigned long); | ||
214 | max -= sizeof(unsigned long); | ||
215 | } | ||
216 | |||
217 | while (count) { | ||
218 | char c; | ||
219 | |||
220 | c = src[res]; | ||
221 | dest[res] = c; | ||
222 | if (!c) | ||
223 | return res; | ||
224 | res++; | ||
225 | count--; | ||
226 | } | ||
227 | |||
228 | /* Hit buffer length without finding a NUL; force NUL-termination. */ | ||
229 | if (res) | ||
230 | dest[res-1] = '\0'; | ||
231 | |||
232 | return -E2BIG; | ||
233 | } | ||
234 | EXPORT_SYMBOL(strscpy); | ||
235 | #endif | ||
236 | |||
149 | #ifndef __HAVE_ARCH_STRCAT | 237 | #ifndef __HAVE_ARCH_STRCAT |
150 | /** | 238 | /** |
151 | * strcat - Append one %NUL-terminated string to another | 239 | * strcat - Append one %NUL-terminated string to another |