[RFC] [2.5 patch] Change strlcpy and strlcat

Adrian Bunk (bunk@fs.tum.de)
Mon, 26 May 2003 15:29:56 +0200


On Mon, May 26, 2003 at 01:13:05AM +0000, Linus Torvalds wrote:
> In article <20030525210509.09429aaa.l.s.r@web.de>,
> René Scharfe <l.s.r@web.de> wrote:
> >
> >Anyway, I corrected this. Patch below contains a "BSD-compatible" version,
> >and also a strlcat().
>
> Ok, I did my own versions, since (a) I had already started and your
> patches wouldn't apply, and (b) I hate adding a zillion lines of extra
> copyright notices for a 5-line function and (c) I think your patch had
> EXPORT_SYMBOL wrong.
>
> In particular, if any architecture ever decides to roll their own
> version of strlcpy/strlcat, the EXPORT_SYMBOL() in ksyms.c would be the
> wrong thing to do.
>
> The current BK tree has my totally untested versions of these functions
> ("Famous last words: 'how hard can it be?'"), along with what I think
> is the proper way to export them.

Your API is compatible with *BSD but I'm wondering whether something
slightly different might make error handling for callers easier:

Currently strlcpy returns the total length of the string it tried to
create, whether it was too long or not. This means a check whether the
complete string was copied is always something like

if (strlcpy(dest, src, sizeof(dest)) >= sizeof(dest))
goto toolong;

If strlcpy would return 0 for successful copies this would simplify to

if (!strlcpy(dest, src, sizeof(dest)))
goto toolong;

A patch is below.

I've tested only the compilation, any comments are welcome.

Another possible change to the semantics might be to copy/cat only if
dest is big enough to make error handling especially in the case of
strlcat easier (without additional information it's currently impossible
to get the original contents of dest if only parts of src were copied).

> Linus

cu
Adrian

--- linux-2.5.69/lib/string.c.old 2003-05-26 11:29:21.000000000 +0200
+++ linux-2.5.69/lib/string.c 2003-05-26 15:19:56.000000000 +0200
@@ -102,20 +102,30 @@
* @src: Where to copy the string from
* @size: size of destination buffer
*
- * Compatible with *BSD: the result is always a valid
+ * Similar to *BSD: the result is always a valid
* NUL-terminated string that fits in the buffer (unless,
* of course, the buffer size is zero). It does not pad
- * out the result like strncpy() does.
+ * out the result like strncpy() does. Unlike *BSD it
+ * returns 0 for a successful copy.
*/
size_t strlcpy(char *dest, const char *src, size_t size)
{
size_t ret = strlen(src);
+ size_t len;
+
+ if (!size)
+ return 0;
+
+ if (ret >= size)
+ len = size - 1;
+ else {
+ len = ret;
+ ret = 0;
+ }
+
+ memcpy(dest, src, len);
+ dest[len] = '\0';

- if (size) {
- size_t len = (ret >= size) ? size-1 : ret;
- memcpy(dest, src, len);
- dest[len] = '\0';
- }
return ret;
}
EXPORT_SYMBOL(strlcpy);
@@ -175,23 +185,33 @@
* @dest: The string to be appended to
* @src: The string to append to it
* @count: The size of the destination buffer.
+ *
+ * Returns 0 if successful, the number of bytes needed in dest
+ * otherwise.
*/
size_t strlcat(char *dest, const char *src, size_t count)
{
size_t dsize = strlen(dest);
size_t len = strlen(src);
- size_t res = dsize + len;
+ size_t ret;

/* This would be a bug */
BUG_ON(dsize >= count);

dest += dsize;
count -= dsize;
+
if (len >= count)
- len = count-1;
+ {
+ ret = dsize + len;
+ len = count - 1;
+ }
+ else
+ ret = 0;
+
memcpy(dest, src, len);
- dest[len] = 0;
- return res;
+ dest[len] = '\0';
+ return ret;
}
EXPORT_SYMBOL(strlcat);
#endif
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/