aboutsummaryrefslogtreecommitdiffstats
path: root/lib/string.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/string.c')
-rw-r--r--lib/string.c88
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)
146EXPORT_SYMBOL(strlcpy); 150EXPORT_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 */
177ssize_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}
234EXPORT_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