FS#10080
* Move strncpy() from core to the pluginlib
* Introduce strlcpy() and use that instead in most places (use memcpy in a few) in core and some plugins
* Drop strncpy() from the codec api as no codec used it
* Bump codec and plugin api versions


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21863 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/bookmark.c b/apps/bookmark.c
index 8c3cc48..892a3d3 100644
--- a/apps/bookmark.c
+++ b/apps/bookmark.c
@@ -1002,17 +1002,14 @@
     if (resume_file != NULL)
     {
         size_t len = (end == NULL) ? strlen(s) : (size_t) (end - s);
-
         len = MIN(resume_file_size - 1, len);
-        strncpy(resume_file, s, len);
-        resume_file[len] = 0;
+        strlcpy(resume_file, s, len + 1);
     }
 
     if (end != NULL && file_name != NULL)
     {
         end++;
-        strncpy(file_name, end, MAX_PATH - 1);
-        file_name[MAX_PATH - 1] = 0;
+        strlcpy(file_name, end, MAX_PATH);
     }
     
     return true;
diff --git a/apps/buffering.c b/apps/buffering.c
index afc444a..08590c9 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -919,7 +919,7 @@
         h->widx = buf_widx;
         h->available = 0;
         h->type = type;
-        strncpy(h->path, file, MAX_PATH);
+        strlcpy(h->path, file, MAX_PATH);
 
         buf_widx += sizeof(struct mp3entry);  /* safe because the handle
                                                  can't wrap */
@@ -952,7 +952,7 @@
         return ERR_BUFFER_FULL;
     }
 
-    strncpy(h->path, file, MAX_PATH);
+    strlcpy(h->path, file, MAX_PATH);
     h->offset = adjusted_offset;
     h->ridx = buf_widx;
     h->widx = buf_widx;
diff --git a/apps/codecs.c b/apps/codecs.c
index c86aeda..0a3dde6 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -122,7 +122,6 @@
 
     /* strings and memory */
     strcpy,
-    strncpy,
     strlen,
     strcmp,
     strcat,
diff --git a/apps/codecs.h b/apps/codecs.h
index 631cf58..b61c3c0 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -75,12 +75,12 @@
 #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */
 
 /* increase this every time the api struct changes */
-#define CODEC_API_VERSION 32
+#define CODEC_API_VERSION 33
 
 /* update this to latest version if a change to the api struct breaks
    backwards compatibility (and please take the opportunity to sort in any
    new function which are "waiting" at the end of the function table) */
-#define CODEC_MIN_API_VERSION 32
+#define CODEC_MIN_API_VERSION 33
 
 /* codec return codes */
 enum codec_status {
@@ -180,7 +180,6 @@
 
     /* strings and memory */
     char* (*strcpy)(char *dst, const char *src);
-    char* (*strncpy)(char *dst, const char *src, size_t length);
     size_t (*strlen)(const char *str);
     int (*strcmp)(const char *, const char *);
     char *(*strcat)(char *s1, const char *s2);
diff --git a/apps/cuesheet.c b/apps/cuesheet.c
index aace64a..fa1d93f 100644
--- a/apps/cuesheet.c
+++ b/apps/cuesheet.c
@@ -84,7 +84,7 @@
         return false;
     }
 
-    strncpy(cuepath, trackpath, MAX_PATH);
+    strlcpy(cuepath, trackpath, MAX_PATH);
     dot = strrchr(cuepath, '.');
     strcpy(dot, ".cue");
 
@@ -103,7 +103,7 @@
     }
 
     if (found_cue_path)
-        strncpy(found_cue_path, cuepath, MAX_PATH);
+        strlcpy(found_cue_path, cuepath, MAX_PATH);
     return true;
 }
 
@@ -205,8 +205,7 @@
                 }
                 else
                 {
-                    strncpy(dest, string, MAX_NAME*3);
-                    dest[MAX_NAME*3] = '\0';
+                    strlcpy(dest, string, MAX_NAME*3 + 1);
                 }
             }    
         }
@@ -218,10 +217,10 @@
     for (i = 0; i < cue->track_count; i++)
     {
         if (*(cue->tracks[i].performer) == '\0')
-            strncpy(cue->tracks[i].performer, cue->performer, MAX_NAME*3);
+            strlcpy(cue->tracks[i].performer, cue->performer, MAX_NAME*3);
 
         if (*(cue->tracks[i].songwriter) == '\0')
-            strncpy(cue->tracks[i].songwriter, cue->songwriter, MAX_NAME*3);
+            strlcpy(cue->tracks[i].songwriter, cue->songwriter, MAX_NAME*3);
     }
 
     return true;
@@ -271,7 +270,7 @@
     struct cuesheet *cue = (struct cuesheet *)data;
 
     if (selected_item & 1)
-        strncpy(buffer, cue->tracks[selected_item/2].title, buffer_len);
+        strlcpy(buffer, cue->tracks[selected_item/2].title, buffer_len);
     else
         snprintf(buffer, buffer_len, "%02d. %s", selected_item/2+1,
                  cue->tracks[selected_item/2].performer);
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 60594b6..648a7e6 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1910,8 +1910,7 @@
 
         if (card->initialized > 0)
         {
-            card_name[6] = '\0';
-            strncpy(card_name, ((unsigned char*)card->cid) + 3, 6);
+            strlcpy(card_name, ((unsigned char*)card->cid) + 3, sizeof(card_name));
             simplelist_addline(SIMPLELIST_ADD_LINE,
                     "%s Rev %d.%d", card_name,
                     (int) card_extract_bits(card->cid, 55, 4),
diff --git a/apps/gui/buttonbar.c b/apps/gui/buttonbar.c
index abf1800..3c343f0 100644
--- a/apps/gui/buttonbar.c
+++ b/apps/gui/buttonbar.c
@@ -86,18 +86,15 @@
     gui_buttonbar_unset(buttonbar);
     if(caption1)
     {
-        strncpy(buttonbar->caption[0], caption1, 7);
-        buttonbar->caption[0][7] = 0;
+        strlcpy(buttonbar->caption[0], caption1, BUTTONBAR_CAPTION_LENGTH);
     }
     if(caption2)
     {
-        strncpy(buttonbar->caption[1], caption2, 7);
-        buttonbar->caption[1][7] = 0;
+        strlcpy(buttonbar->caption[1], caption2, BUTTONBAR_CAPTION_LENGTH);
     }
     if(caption3)
     {
-        strncpy(buttonbar->caption[2], caption3, 7);
-        buttonbar->caption[2][7] = 0;
+        strlcpy(buttonbar->caption[2], caption3, BUTTONBAR_CAPTION_LENGTH);
     }
 }
 
diff --git a/apps/gui/gwps-common.c b/apps/gui/gwps-common.c
index f480f61..c0923a9 100644
--- a/apps/gui/gwps-common.c
+++ b/apps/gui/gwps-common.c
@@ -659,8 +659,7 @@
         return NULL;
 
     len = MIN(last_sep - sep, buf_size - 1);
-    strncpy(buf, sep + 1, len);
-    buf[len] = 0;
+    strlcpy(buf, sep + 1, len + 1);
     return buf;
 }
 
@@ -1183,12 +1182,12 @@
             {
                 /* we need 11 characters (full line) for
                     progress-bar */
-                strncpy(buf, "           ", buf_size);
+                strlcpy(buf, "           ", buf_size);
             }
             else
             {
                 /* Tell the user if we have an OldPlayer */
-                strncpy(buf, " <Old LCD> ", buf_size);
+                strlcpy(buf, " <Old LCD> ", buf_size);
             }
             return buf;
 #endif
@@ -1254,11 +1253,11 @@
                     break;
                 case 2:
                 case 4:
-                    strncpy(buf, id3->track_gain_string, buf_size);
+                    strlcpy(buf, id3->track_gain_string, buf_size);
                     break;
                 case 3:
                 case 5:
-                    strncpy(buf, id3->album_gain_string, buf_size);
+                    strlcpy(buf, id3->album_gain_string, buf_size);
                     break;
             }
             return buf;
diff --git a/apps/gui/option_select.c b/apps/gui/option_select.c
index 7b6c489..01259c4 100644
--- a/apps/gui/option_select.c
+++ b/apps/gui/option_select.c
@@ -76,7 +76,7 @@
     if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
     {
         bool val = (bool)temp_var;
-        strncpy(buffer, str(val? setting->bool_setting->lang_yes :
+        strlcpy(buffer, str(val? setting->bool_setting->lang_yes :
                                  setting->bool_setting->lang_no), buf_len);
     }
 #if 0 /* probably dont need this one */
@@ -137,7 +137,7 @@
             const struct choice_setting *info = setting->choice_setting;
             if (info->talks[(int)temp_var] < LANG_LAST_INDEX_IN_ARRAY)
             {
-                strncpy(buffer, str(info->talks[(int)temp_var]), buf_len);
+                strlcpy(buffer, str(info->talks[(int)temp_var]), buf_len);
             }
             else
             {
@@ -149,7 +149,7 @@
         {
             int value= (int)temp_var;
             char *val = P2STR(setting->choice_setting->desc[value]);
-            strncpy(buffer, val, buf_len);
+            strlcpy(buffer, val, buf_len);
         }
     }
     return buffer;
diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c
index 47dcb4e..5e21509 100644
--- a/apps/gui/statusbar.c
+++ b/apps/gui/statusbar.c
@@ -617,7 +617,7 @@
         snprintf(buffer, sizeof(buffer), "%02d:%02d", hour, minute);
     }
     else {
-        strncpy(buffer, "--:--", sizeof buffer);
+        strlcpy(buffer, "--:--", sizeof(buffer));
     }
     display->setfont(FONT_SYSFIXED);
     display->getstringsize(buffer, &width, &height);
@@ -626,7 +626,6 @@
                         STATUSBAR_Y_POS, buffer);
     }
     display->setfont(FONT_UI);
-
 }
 #endif
 
@@ -758,14 +757,14 @@
     if (global_settings.rec_source == AUDIO_SRC_SPDIF)
     {
         /* Can't measure S/PDIF sample rate on Archos/Sim yet */
-        strncpy(buffer, "--", sizeof(buffer));
+        strlcpy(buffer, "--", sizeof(buffer));
     }
     else
 #endif /* HAVE_SPDIF_IN */
     {
         static char const * const freq_strings[12] =
         { "44", "48", "32", "22", "24", "16" };
-        strncpy(buffer, freq_strings[global_settings.rec_frequency],
+        strlcpy(buffer, freq_strings[global_settings.rec_frequency],
                 sizeof(buffer));
     }
 
diff --git a/apps/gui/wps_parser.c b/apps/gui/wps_parser.c
index 09bcab8..8ae8392 100644
--- a/apps/gui/wps_parser.c
+++ b/apps/gui/wps_parser.c
@@ -1489,8 +1489,7 @@
                             break;
                         }
 
-                        strncpy(stringbuf, string_start, len);
-                        *(stringbuf + len) = '\0';
+                        strlcpy(stringbuf, string_start, len+1);
 
                         data->strings[data->num_strings] = stringbuf;
                         stringbuf += len + 1;
@@ -1781,11 +1780,9 @@
 #ifdef HAVE_LCD_BITMAP
         /* get the bitmap dir */
         char bmpdir[MAX_PATH];
-        size_t bmpdirlen;
         char *dot = strrchr(buf, '.');
-        bmpdirlen = dot - buf;
-        strncpy(bmpdir, buf, dot - buf);
-        bmpdir[bmpdirlen] = 0;
+
+        strlcpy(bmpdir, buf, dot - buf + 1);
 
         /* load the bitmaps that were found by the parsing */
         if (!load_wps_bitmaps(wps_data, bmpdir)) {
diff --git a/apps/iap.c b/apps/iap.c
index 51f5e59..592bbdb 100644
--- a/apps/iap.c
+++ b/apps/iap.c
@@ -495,6 +495,7 @@
                 unsigned char data[70] = {0x04, 0x00, 0xFF};
                 struct mp3entry id3;
                 int fd;
+                size_t len;
                 long tracknum = (signed long)serbuf[4] << 24 |
                                 (signed long)serbuf[5] << 16 |
                                 (signed long)serbuf[6] << 8 | serbuf[7];
@@ -520,16 +521,16 @@
                 switch(serbuf[3])
                 {
                     case 0x20:
-                        strncpy((char *)&data[3], id3.title, 64);
-                            iap_send_pkt(data, 4+strlen(id3.title));
+                        len = strlcpy((char *)&data[3], id3.title, 64);
+                            iap_send_pkt(data, 4+len);
                         break;
                     case 0x22:
-                        strncpy((char *)&data[3], id3.artist, 64);
-                            iap_send_pkt(data, 4+strlen(id3.artist));
+                        len = strlcpy((char *)&data[3], id3.artist, 64);
+                            iap_send_pkt(data, 4+len);
                         break;
                     case 0x24:
-                        strncpy((char *)&data[3], id3.album, 64);
-                            iap_send_pkt(data, 4+strlen(id3.album));
+                        len = strlcpy((char *)&data[3], id3.album, 64);
+                            iap_send_pkt(data, 4+len);
                         break;
                 }
                 break;
diff --git a/apps/menu.c b/apps/menu.c
index aff84c7..f6d0ef9 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -321,7 +321,7 @@
         while (i < MAX_PATH-1)
         {
             int padlen = MIN(len, MAX_PATH-1-i);
-            strncpy(&padded_title[i], title, padlen);
+            strlcpy(&padded_title[i], title, padlen);
             i += padlen;
             if (i<MAX_PATH-1)
                 padded_title[i++] = ' ';
diff --git a/apps/menus/main_menu.c b/apps/menus/main_menu.c
index 01b4dbe..76ed01d 100644
--- a/apps/menus/main_menu.c
+++ b/apps/menus/main_menu.c
@@ -425,7 +425,7 @@
         minutes = value - (hours * 60);
         snprintf(buffer, buffer_size, "%d:%02d", hours, minutes);
    } else {
-        strncpy(buffer, str(LANG_OFF), buffer_size);
+        strlcpy(buffer, str(LANG_OFF), buffer_size);
     }
 }
 
diff --git a/apps/metadata.c b/apps/metadata.c
index 6003e19..b995e11 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -403,7 +403,7 @@
 #endif
     
     lseek(fd, 0, SEEK_SET);
-    strncpy(id3->path, trackname, sizeof(id3->path));
+    strlcpy(id3->path, trackname, sizeof(id3->path));
 
     return true;
 }
diff --git a/apps/metadata/metadata_common.c b/apps/metadata/metadata_common.c
index 38761e3..5947098 100644
--- a/apps/metadata/metadata_common.c
+++ b/apps/metadata/metadata_common.c
@@ -320,10 +320,9 @@
 
         if (len > 0)
         {
-            strncpy(buf, value, len);
-            buf[len] = 0;
-            *p = buf;
             len++;
+            strlcpy(buf, value, len);
+            *p = buf;
         }
         else
         {
diff --git a/apps/metadata/mp3.c b/apps/metadata/mp3.c
index d3adc5d..f027000 100644
--- a/apps/metadata/mp3.c
+++ b/apps/metadata/mp3.c
@@ -309,8 +309,7 @@
         value_len = bufferpos - (tag - entry->id3v2buf);
         
         if (!strcasecmp(tag, "ALBUM ARTIST")) {
-            strncpy(tag, value, value_len);
-            tag[value_len - 1] = 0;
+            strlcpy(tag, value, value_len);
             entry->albumartist = tag;
 #if CONFIG_CODEC == SWCODEC
         } else {
@@ -1114,7 +1113,7 @@
     memset(entry, 0, sizeof(struct mp3entry));
 #endif
 
-    strncpy(entry->path, filename, sizeof(entry->path));
+    strlcpy(entry->path, filename, sizeof(entry->path));
 
     entry->title = NULL;
     entry->filesize = filesize(fd);
diff --git a/apps/misc.c b/apps/misc.c
index cf356a3..e6f8ca8 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -814,15 +814,13 @@
     {
         len = dot - filename;
         len = MIN(len, buffer_size);
-        strncpy(buffer, filename, len);
     }
     else
     {
         len = buffer_size;
-        strncpy(buffer, filename, buffer_size);
     }
 
-    buffer[len] = 0;
+    strlcpy(buffer, filename, len + 1);
 
     return buffer;
 }
diff --git a/apps/mpeg.c b/apps/mpeg.c
index 8518ab6..0e1217b 100644
--- a/apps/mpeg.c
+++ b/apps/mpeg.c
@@ -2203,8 +2203,7 @@
 {
     mpeg_errno = 0;
     
-    strncpy(recording_filename, filename, MAX_PATH - 1);
-    recording_filename[MAX_PATH - 1] = 0;
+    strlcpy(recording_filename, filename, MAX_PATH);
 
     queue_post(&mpeg_queue, MPEG_RECORD, 0);
 }
@@ -2509,8 +2508,7 @@
 {
     mpeg_errno = 0;
 
-    strncpy(recording_filename, filename, MAX_PATH - 1);
-    recording_filename[MAX_PATH - 1] = 0;
+    strlcpy(recording_filename, filename, MAX_PATH);
 
     queue_post(&mpeg_queue, MPEG_NEW_FILE, 0);
 }
diff --git a/apps/onplay.c b/apps/onplay.c
index 621bf82..9f38b32 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -532,7 +532,7 @@
     {
         char pathname[MAX_PATH]; /* space to go deep */
         cpu_boost(true);
-        strncpy(pathname, file_to_delete, sizeof pathname);
+        strlcpy(pathname, file_to_delete, sizeof(pathname));
         res = remove_dir(pathname, sizeof(pathname));
         cpu_boost(false);
     }
@@ -578,7 +578,7 @@
     char newname[MAX_PATH];
     char* ptr = strrchr(selected_file, '/') + 1;
     int pathlen = (ptr - selected_file);
-    strncpy(newname, selected_file, sizeof newname);
+    strlcpy(newname, selected_file, sizeof(newname));
     if (!kbd_input(newname + pathlen, (sizeof newname)-pathlen)) {
         if (!strlen(newname + pathlen) ||
             (rename(selected_file, newname) < 0)) {
@@ -638,7 +638,7 @@
 static bool clipboard_clip(bool copy)
 {
     clipboard_selection[0] = 0;
-    strncpy(clipboard_selection, selected_file, sizeof(clipboard_selection));
+    strlcpy(clipboard_selection, selected_file, sizeof(clipboard_selection));
     clipboard_selection_attr = selected_file_attr;
     clipboard_is_copy = copy;
 
@@ -895,15 +895,15 @@
         }
         else
         {
-            strncpy(srcpath, clipboard_selection, sizeof(srcpath));
-            strncpy(targetpath, target, sizeof(targetpath));
+            strlcpy(srcpath, clipboard_selection, sizeof(srcpath));
+            strlcpy(targetpath, target, sizeof(targetpath));
     
             success = clipboard_pastedirectory(srcpath, sizeof(srcpath),
                              target, sizeof(targetpath), clipboard_is_copy);
 
             if (success && !clipboard_is_copy)
             {
-                strncpy(srcpath, clipboard_selection, sizeof(srcpath));
+                strlcpy(srcpath, clipboard_selection, sizeof(srcpath));
                 remove_dir(srcpath, sizeof(srcpath));
             }
         }
@@ -1026,7 +1026,7 @@
 #ifdef HAVE_RECORDING
 static bool set_recdir(void)
 {
-    strncpy(global_settings.rec_directory,
+    strlcpy(global_settings.rec_directory,
             selected_file, MAX_FILENAME+1);
     settings_save();
     return false;
diff --git a/apps/playback.c b/apps/playback.c
index 4af457c..cee89d3 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -617,7 +617,7 @@
         return write_id3;
 #endif
 
-    strncpy(write_id3->path, filename, sizeof(write_id3->path)-1);
+    strlcpy(write_id3->path, filename, sizeof(write_id3->path));
     write_id3->title = strrchr(write_id3->path, '/');
     if (!write_id3->title)
         write_id3->title = &write_id3->path[0];
diff --git a/apps/playlist.c b/apps/playlist.c
index 1d291cf..b70fdc8 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -1349,8 +1349,7 @@
     
     if (playlist->in_ram && !control_file && max < 0)
     {
-        strncpy(tmp_buf, &playlist->buffer[seek], sizeof(tmp_buf));
-        tmp_buf[MAX_PATH] = '\0';
+        strlcpy(tmp_buf, &playlist->buffer[seek], sizeof(tmp_buf));
         max = strlen(tmp_buf) + 1;
     }
     else if (max < 0)
@@ -1402,8 +1401,7 @@
         }
     }
 
-    strncpy(dir_buf, playlist->filename, playlist->dirlen-1);
-    dir_buf[playlist->dirlen-1] = 0;
+    strlcpy(dir_buf, playlist->filename, playlist->dirlen);
 
     return (format_track_path(buf, tmp_buf, buf_length, max, dir_buf));
 }
@@ -1471,8 +1469,7 @@
     else
     {
         /* start with current directory */
-        strncpy(dir, playlist->filename, playlist->dirlen-1);
-        dir[playlist->dirlen-1] = '\0';
+        strlcpy(dir, playlist->filename, playlist->dirlen);
     }
 
     /* use the tree browser dircache to load files */
@@ -1671,13 +1668,13 @@
 
     if('/' == src[0])
     {
-        strncpy(dest, src, buf_length);
+        strlcpy(dest, src, buf_length);
     }
     else
     {
         /* handle dos style drive letter */
         if (':' == src[1])
-            strncpy(dest, &src[2], buf_length);
+            strlcpy(dest, &src[2], buf_length);
         else if (!strncmp(src, "../", 3))
         {
             /* handle relative paths */
@@ -1904,7 +1901,7 @@
     struct playlist_info* playlist = &current_playlist;
 
     playlist->current = true;
-    strncpy(playlist->control_filename, PLAYLIST_CONTROL_FILE,
+    strlcpy(playlist->control_filename, PLAYLIST_CONTROL_FILE,
             sizeof(playlist->control_filename));
     playlist->fd = -1;
     playlist->control_fd = -1;
@@ -2721,7 +2718,7 @@
 
     empty_playlist(&current_playlist, false);
 
-    strncpy(current_playlist.filename, playlist->filename,
+    strlcpy(current_playlist.filename, playlist->filename,
         sizeof(current_playlist.filename));
 
     current_playlist.utf8 = playlist->utf8;
@@ -3240,7 +3237,7 @@
     if (!playlist)
         playlist = &current_playlist;
 
-    strncpy(buf, playlist->filename+playlist->dirlen, buf_size);
+    strlcpy(buf, playlist->filename+playlist->dirlen, buf_size);
   
     if (!buf[0])
         return NULL;
@@ -3260,7 +3257,7 @@
     if (!playlist)
         playlist = &current_playlist;
 
-    strncpy(buf, playlist->filename, buf_size);
+    strlcpy(buf, playlist->filename, buf_size);
 
     if (!buf[0])
         return NULL;
diff --git a/apps/playlist_catalog.c b/apps/playlist_catalog.c
index 84a62e3..a4950e2 100644
--- a/apps/playlist_catalog.c
+++ b/apps/playlist_catalog.c
@@ -78,7 +78,7 @@
 
         /* fall back to default directory if no or invalid config */
         if (default_dir)
-            strncpy(playlist_dir, PLAYLIST_CATALOG_DEFAULT_DIR,
+            strlcpy(playlist_dir, PLAYLIST_CATALOG_DEFAULT_DIR,
                 sizeof(playlist_dir));
 
         playlist_dir_length = strlen(playlist_dir);
@@ -189,7 +189,7 @@
 {
     char** playlists = (char**) data;
 
-    strncpy(buffer, playlists[selected_item], buffer_len);
+    strlcpy(buffer, playlists[selected_item], buffer_len);
 
     if (buffer[0] != '.' && !(global_settings.show_filename_ext == 1
         || (global_settings.show_filename_ext == 3
@@ -478,7 +478,7 @@
 
     if (add_to_playlist(playlist, new_playlist, sel, sel_attr) == 0)
     {
-        strncpy(most_recent_playlist, playlist+playlist_dir_length+1,
+        strlcpy(most_recent_playlist, playlist+playlist_dir_length+1,
             sizeof(most_recent_playlist));
         return true;
     }
diff --git a/apps/plugin.c b/apps/plugin.c
index f08a987..b8c4efd 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -381,7 +381,7 @@
     snprintf,
     vsnprintf,
     strcpy,
-    strncpy,
+    strlcpy,
     strlen,
     strrchr,
     strcmp,
diff --git a/apps/plugin.h b/apps/plugin.h
index bb74d73..35b2105 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -38,6 +38,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+char* strncpy(char *, const char *, size_t);
 void* plugin_get_buffer(size_t *buffer_size);
 
 #ifndef __PCTOOL__
@@ -128,12 +129,12 @@
 #define PLUGIN_MAGIC 0x526F634B /* RocK */
 
 /* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 160
+#define PLUGIN_API_VERSION 161
 
 /* update this to latest version if a change to the api struct breaks
    backwards compatibility (and please take the opportunity to sort in any
    new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 160
+#define PLUGIN_MIN_API_VERSION 161
 
 /* plugin return codes */
 enum plugin_status {
@@ -505,7 +506,7 @@
                     ATTRIBUTE_PRINTF(3, 4);
     int (*vsnprintf)(char *buf, int size, const char *fmt, va_list ap);
     char* (*strcpy)(char *dst, const char *src);
-    char* (*strncpy)(char *dst, const char *src, size_t length);
+    size_t (*strlcpy)(char *dst, const char *src, size_t length);
     size_t (*strlen)(const char *str);
     char * (*strrchr)(const char *s, int c);
     int (*strcmp)(const char *, const char *);
diff --git a/apps/plugins/chessbox/chessbox_pgn.c b/apps/plugins/chessbox/chessbox_pgn.c
index a8be179..cd163a5 100644
--- a/apps/plugins/chessbox/chessbox_pgn.c
+++ b/apps/plugins/chessbox/chessbox_pgn.c
@@ -543,7 +543,7 @@
     rb->snprintf(text_buffer, 50,"%s vs. %s (%s)", temp_node->white_player,
                          temp_node->black_player, temp_node->game_date);
 
-    rb->strncpy(buffer, text_buffer, buffer_len);
+    rb->strlcpy(buffer, text_buffer, buffer_len);
     return buffer;
 }
 
diff --git a/apps/plugins/dict.c b/apps/plugins/dict.c
index 0c1ddf3..fcc55fa 100644
--- a/apps/plugins/dict.c
+++ b/apps/plugins/dict.c
@@ -283,8 +283,7 @@
     while (1)
     {
         /* copy one lcd line */
-        rb->strncpy(output, ptr, display_columns);
-        output[display_columns] = '\0';
+        rb->strlcpy(output, ptr, display_columns + 1);
 
         /* typecast to kill a warning... */
         if((int)rb->strlen(ptr) < display_columns)
diff --git a/apps/plugins/doom/rockmacros.h b/apps/plugins/doom/rockmacros.h
index 73cd902..1ead411 100644
--- a/apps/plugins/doom/rockmacros.h
+++ b/apps/plugins/doom/rockmacros.h
@@ -59,7 +59,6 @@
 #define memcmp(a,b,c)      rb->memcmp((a),(b),(c))
 #define memchr(a,b,c)      rb->memchr((a),(b),(c))
 #define strcpy(a,b)        rb->strcpy((a),(b))
-#define strncpy(a,b,c)     rb->strncpy((a),(b),(c))
 #define strlen(a)          rb->strlen((a))
 #define strcmp(a,b)        rb->strcmp((a),(b))
 #define strncmp(a,b,c)     rb->strncmp((a),(b),(c))
diff --git a/apps/plugins/goban/sgf_output.c b/apps/plugins/goban/sgf_output.c
index c1ac052..6a52789 100644
--- a/apps/plugins/goban/sgf_output.c
+++ b/apps/plugins/goban/sgf_output.c
@@ -130,7 +130,7 @@
 {
     char buffer[128];
 
-    rb->strncpy (buffer, "GM[1]FF[4]CA[UTF-8]AP[Rockbox Goban:1.0]ST[2]\n\n",
+    rb->strlcpy (buffer, "GM[1]FF[4]CA[UTF-8]AP[Rockbox Goban:1.0]ST[2]\n\n",
                  sizeof (buffer));
     write_file (sgf_fd, buffer, rb->strlen (buffer));
 
diff --git a/apps/plugins/invadrox.c b/apps/plugins/invadrox.c
index c7d5696..fa7cb81 100644
--- a/apps/plugins/invadrox.c
+++ b/apps/plugins/invadrox.c
@@ -1511,7 +1511,7 @@
 
     if (highscore_load(HISCOREFILE, &hiscore, 1) < 0) {
         /* Init hiscore to 0 */
-        rb->strncpy(hiscore.name, "Invader", sizeof(hiscore.name));
+        rb->strlcpy(hiscore.name, "Invader", sizeof(hiscore.name));
         hiscore.score = 0;
         hiscore.level = 1;
     }
diff --git a/apps/plugins/keybox.c b/apps/plugins/keybox.c
index 08d5131..73fd138 100644
--- a/apps/plugins/keybox.c
+++ b/apps/plugins/keybox.c
@@ -330,11 +330,11 @@
 static void make_key(void)
 {
     int i;
-    char buf[sizeof(master_pw) + sizeof(salt) + 1];
+    char buf[sizeof(master_pw) + sizeof(salt) + 1] = {0};
     struct md5_s key_md5;
     size_t len = rb->strlen(master_pw);
 
-    rb->strncpy(buf, master_pw, sizeof(buf));
+    rb->strlcpy(buf, master_pw, sizeof(buf));
 
     rb->memcpy(&buf[len], &salt, sizeof(salt));
 
@@ -418,7 +418,7 @@
             break;
         }
 
-        rb->strncpy(entry->title, start, FIELD_LEN);
+        rb->strlcpy(entry->title, start, FIELD_LEN);
         start = end + 1;
 
         end = rb->strchr(start, '\0'); /* find eol */
@@ -428,7 +428,7 @@
             break;
         }
 
-        rb->strncpy(entry->name, start, FIELD_LEN);
+        rb->strlcpy(entry->name, start, FIELD_LEN);
         start = end + 1;
 
         end = rb->strchr(start, '\0'); /* find eol */
@@ -437,7 +437,7 @@
         {
             break;
         }
-        rb->strncpy(entry->password, start, FIELD_LEN);
+        rb->strlcpy(entry->password, start, FIELD_LEN);
         start = end + 1;
         entry->used = true;
         if (i + 1 < MAX_ENTRIES - 1)
@@ -469,13 +469,13 @@
     for (i = 0; i < pw_list.num_entries; i++)
     {
         len = rb->strlen(entry->title);
-        rb->strncpy(p, entry->title, len+1);
+        rb->strlcpy(p, entry->title, len+1);
         p += len+1;
         len = rb->strlen(entry->name);
-        rb->strncpy(p, entry->name, len+1);
+        rb->strlcpy(p, entry->name, len+1);
         p += len+1;
         len = rb->strlen(entry->password);
-        rb->strncpy(p, entry->password, len+1);
+        rb->strlcpy(p, entry->password, len+1);
         p += len+1;
         if (entry->next)
             entry = entry->next;
@@ -517,7 +517,7 @@
         }
         else
         {
-            rb->strncpy(pw_buf, buf[0], buflen);
+            rb->strlcpy(pw_buf, buf[0], buflen);
             hash_pw(&pwhash);
             return 0;
         }
diff --git a/apps/plugins/lib/SOURCES b/apps/plugins/lib/SOURCES
index 02adb70..72538fc 100644
--- a/apps/plugins/lib/SOURCES
+++ b/apps/plugins/lib/SOURCES
@@ -6,6 +6,7 @@
 rgb_hsv.c
 buflib.c
 display_text.c
+strncpy.c
 #if defined(HAVE_LCD_BITMAP) && (LCD_DEPTH < 4)
 grey_core.c
 grey_draw.c
diff --git a/apps/plugins/lib/configfile.c b/apps/plugins/lib/configfile.c
index 5e1e776..21b66a3 100644
--- a/apps/plugins/lib/configfile.c
+++ b/apps/plugins/lib/configfile.c
@@ -139,7 +139,7 @@
                         break;
 
                     case TYPE_STRING:
-                        rb->strncpy(cfg[i].string, val, cfg[i].max);
+                        rb->strlcpy(cfg[i].string, val, cfg[i].max);
                         break;
                 }
             }
diff --git a/apps/plugins/lib/highscore.c b/apps/plugins/lib/highscore.c
index e8e1c88..15ebb05 100644
--- a/apps/plugins/lib/highscore.c
+++ b/apps/plugins/lib/highscore.c
@@ -72,7 +72,7 @@
 
         scores[i].score = rb->atoi(score);
         scores[i].level = rb->atoi(level);
-        rb->strncpy(scores[i].name, name, sizeof(scores[i].name)-1);
+        rb->strlcpy(scores[i].name, name, sizeof(scores[i].name));
         i++;
     }
     rb->close(fd);
@@ -100,8 +100,7 @@
     entry = scores + pos;
     entry->score = score;
     entry->level = level;
-    rb->strncpy(entry->name, name, sizeof(entry->name));
-    entry->name[sizeof(entry->name)-1] = '\0';
+    rb->strlcpy(entry->name, name, sizeof(entry->name));
 
     return pos;
 }
diff --git a/firmware/common/strncpy.c b/apps/plugins/lib/strncpy.c
similarity index 100%
rename from firmware/common/strncpy.c
rename to apps/plugins/lib/strncpy.c
diff --git a/apps/plugins/lib/wrappers.h b/apps/plugins/lib/wrappers.h
index 5eb45d0..b6fbd51 100644
--- a/apps/plugins/lib/wrappers.h
+++ b/apps/plugins/lib/wrappers.h
@@ -51,7 +51,7 @@
 #define strcpy rb->strcpy
 #define strip_extension rb->strip_extension
 #define strlen rb->strlen
-#define strncpy rb->strncpy
+#define strlcpy rb->strlcpy
 #define strrchr rb->strrchr
 
 #endif
diff --git a/apps/plugins/lua/lobject.c b/apps/plugins/lua/lobject.c
index 62ad8e9..7f73114 100644
--- a/apps/plugins/lua/lobject.c
+++ b/apps/plugins/lua/lobject.c
@@ -181,8 +181,7 @@
 
 void luaO_chunkid (char *out, const char *source, size_t bufflen) {
   if (*source == '=') {
-    strncpy(out, source+1, bufflen);  /* remove first char */
-    out[bufflen-1] = '\0';  /* ensures null termination */
+    strlcpy(out, source+1, bufflen);  /* remove first char */
   }
   else {  /* out = "source", or "...source" */
     if (*source == '@') {
diff --git a/apps/plugins/lua/lstrlib.c b/apps/plugins/lua/lstrlib.c
index 3d61036..4d58280 100644
--- a/apps/plugins/lua/lstrlib.c
+++ b/apps/plugins/lua/lstrlib.c
@@ -737,9 +737,7 @@
   if (isdigit(uchar(*p)))
     luaL_error(L, "invalid format (width or precision too long)");
   *(form++) = '%';
-  strncpy(form, strfrmt, p - strfrmt + 1);
-  form += p - strfrmt + 1;
-  *form = '\0';
+  strlcpy(form, strfrmt, p - strfrmt + 1);
   return p;
 }
 
diff --git a/apps/plugins/lua/rockconf.h b/apps/plugins/lua/rockconf.h
index 639f336..02bd0e7 100644
--- a/apps/plugins/lua/rockconf.h
+++ b/apps/plugins/lua/rockconf.h
@@ -63,7 +63,7 @@
 #define strchr   rb->strchr
 #define strcmp   rb->strcmp
 #define strcpy   rb->strcpy
-#define strncpy  rb->strncpy
+#define strlcpy  rb->strlcpy
 #define strlen   rb->strlen
 
 #endif /* _ROCKCONF_H_ */
diff --git a/apps/plugins/mp3_encoder.c b/apps/plugins/mp3_encoder.c
index 6849daf..9da0d69 100644
--- a/apps/plugins/mp3_encoder.c
+++ b/apps/plugins/mp3_encoder.c
@@ -2399,9 +2399,8 @@
 
 void get_mp3_filename(const char *wav_name)
 {
-    int slen = rb->strlen(wav_name);
-    rb->strncpy(mp3_name, wav_name, 79);
-    rb->strncpy(mp3_name + slen - 4, ".mp3", 5);
+    rb->strlcpy(mp3_name, wav_name, sizeof(mp3_name));
+    rb->strlcpy(mp3_name + rb->strlen(mp3_name) - 4, ".mp3", 5);
 }
 
 #if CONFIG_KEYPAD == IRIVER_H100_PAD || CONFIG_KEYPAD == IRIVER_H300_PAD
diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c
index 7ec1157..a9b66fc 100644
--- a/apps/plugins/mpegplayer/mpeg_settings.c
+++ b/apps/plugins/mpegplayer/mpeg_settings.c
@@ -344,7 +344,7 @@
                                            int value, const char *input)
 {
     if (value < 0)
-        rb->strncpy(buf, BACKLIGHT_OPTION_DEFAULT, length);
+        rb->strlcpy(buf, BACKLIGHT_OPTION_DEFAULT, length);
     else
         rb->snprintf(buf, length, "%d", value + MIN_BRIGHTNESS_SETTING);
 
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c
index 496e9c9..34d1db5 100644
--- a/apps/plugins/pictureflow/pictureflow.c
+++ b/apps/plugins/pictureflow/pictureflow.c
@@ -913,7 +913,7 @@
 {
     if ( slide_index == -1 )
     {
-        rb->strncpy( buf, EMPTY_SLIDE, buflen );
+        rb->strlcpy( buf, EMPTY_SLIDE, buflen );
     }
 
     if (!rb->tagcache_search(&tcs, tag_filename))
@@ -930,8 +930,7 @@
 #ifdef HAVE_TC_RAMCACHE
         if (rb->tagcache_fill_tags(&id3, tcs.result))
         {
-            rb->strncpy(id3.path, tcs.result, sizeof(id3.path));
-            id3.path[sizeof(id3.path) - 1] = 0;
+            rb->strlcpy(id3.path, tcs.result, sizeof(id3.path));
         }
         else
 #endif
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c
index 18beec2..b57150b 100644
--- a/apps/plugins/properties.c
+++ b/apps/plugins/properties.c
@@ -70,8 +70,7 @@
 
     char* ptr = rb->strrchr(selected_file, '/') + 1;
     int dirlen = (ptr - selected_file);
-    rb->strncpy(tstr, selected_file, dirlen);
-    tstr[dirlen] = 0;
+    rb->strlcpy(tstr, selected_file, dirlen + 1);
 
     dir = rb->opendir(tstr);
     if (dir)
@@ -212,7 +211,7 @@
 {
     DPS dps;
     char tstr[64];
-    rb->strncpy(dps.dirname, selected_file, MAX_PATH);
+    rb->strlcpy(dps.dirname, selected_file, MAX_PATH);
     dps.len = MAX_PATH;
     dps.dc = 0;
     dps.fc = 0;
@@ -220,7 +219,7 @@
     if(false == _dir_properties(&dps))
         return false;
 
-    rb->strncpy(str_dirname, selected_file, MAX_PATH);
+    rb->strlcpy(str_dirname, selected_file, MAX_PATH);
     rb->snprintf(str_dircount, sizeof str_dircount, "Subdirs: %d", dps.dc);
     rb->snprintf(str_filecount, sizeof str_filecount, "Files: %d", dps.fc);
     rb->snprintf(str_size, sizeof str_size, "Size: %s",
@@ -236,35 +235,35 @@
     switch(selected_item)
     {
         case 0:
-            rb->strncpy(buffer, str_dirname, buffer_len);
+            rb->strlcpy(buffer, str_dirname, buffer_len);
             break;
         case 1:
-            rb->strncpy(buffer, its_a_dir ? str_dircount : str_filename,
+            rb->strlcpy(buffer, its_a_dir ? str_dircount : str_filename,
                         buffer_len);
             break;
         case 2:
-            rb->strncpy(buffer, its_a_dir ? str_filecount : str_size, buffer_len);
+            rb->strlcpy(buffer, its_a_dir ? str_filecount : str_size, buffer_len);
             break;
         case 3:
-            rb->strncpy(buffer, its_a_dir ? str_size : str_date, buffer_len);
+            rb->strlcpy(buffer, its_a_dir ? str_size : str_date, buffer_len);
             break;
         case 4:
-            rb->strncpy(buffer, its_a_dir ? "" : str_time, buffer_len);
+            rb->strlcpy(buffer, its_a_dir ? "" : str_time, buffer_len);
             break;
         case 5:
-            rb->strncpy(buffer, its_a_dir ? "" : str_artist, buffer_len);
+            rb->strlcpy(buffer, its_a_dir ? "" : str_artist, buffer_len);
             break;
         case 6:
-            rb->strncpy(buffer, its_a_dir ? "" : str_title, buffer_len);
+            rb->strlcpy(buffer, its_a_dir ? "" : str_title, buffer_len);
             break;
         case 7:
-            rb->strncpy(buffer, its_a_dir ? "" : str_album, buffer_len);
+            rb->strlcpy(buffer, its_a_dir ? "" : str_album, buffer_len);
             break;
         case 8:
-            rb->strncpy(buffer, its_a_dir ? "" : str_duration, buffer_len);
+            rb->strlcpy(buffer, its_a_dir ? "" : str_duration, buffer_len);
             break;
         default:
-            rb->strncpy(buffer, "ERROR", buffer_len);
+            rb->strlcpy(buffer, "ERROR", buffer_len);
             break;
     }
     return buffer;
@@ -284,8 +283,7 @@
     struct dirent* entry;
     char* ptr = rb->strrchr(file, '/') + 1;
     int dirlen = (ptr - file);
-    rb->strncpy(str_dirname, file, dirlen);
-    str_dirname[dirlen] = 0;
+    rb->strlcpy(str_dirname, file, dirlen + 1);
 
     dir = rb->opendir(str_dirname);
     if (dir)
diff --git a/apps/plugins/random_folder_advance_config.c b/apps/plugins/random_folder_advance_config.c
index 28546a3..c9ffaed 100644
--- a/apps/plugins/random_folder_advance_config.c
+++ b/apps/plugins/random_folder_advance_config.c
@@ -86,7 +86,7 @@
         /* check if path is removed directory, if so dont enter it */
         rb->snprintf(path, MAX_PATH, "%s/%s", fullpath, entry->d_name);
         while(path[0] == '/')
-            rb->strncpy(path, path + 1, rb->strlen(path));
+            rb->strlcpy(path, path + 1, sizeof(path));
         for(i = 0; i < num_replaced_dirs; i++)
         {
             if(!rb->strcmp(path, removed_dirs[i]))
@@ -141,8 +141,8 @@
                      (num_replaced_dirs < MAX_REMOVED_DIRS))
             {
                 num_replaced_dirs ++;
-                rb->strncpy(removed_dirs[num_replaced_dirs - 1], line + 2,
-                                rb->strlen(line));
+                rb->strlcpy(removed_dirs[num_replaced_dirs - 1], line + 2,
+                                sizeof(line));
             }
         }
         rb->close(fd2);
@@ -157,7 +157,7 @@
             {
                 /* remove preceeding '/'s from the line */
                 while(line[0] == '/')
-                    rb->strncpy(line, line + 1, rb->strlen(line));
+                    rb->strlcpy(line, line + 1, sizeof(line));
 
                 rb->snprintf(formatted_line, MAX_PATH, "/%s", line);
 
@@ -237,7 +237,7 @@
 char *list_get_name_cb(int selected_item, void* data, char* buf, size_t buf_len)
 {
     (void)data;
-    rb->strncpy(buf, list->folder[selected_item], buf_len);
+    rb->strlcpy(buf, list->folder[selected_item], buf_len);
     return buf;
 }
 
diff --git a/apps/plugins/rockboy/menu.c b/apps/plugins/rockboy/menu.c
index 9821ce9..76de224 100644
--- a/apps/plugins/rockboy/menu.c
+++ b/apps/plugins/rockboy/menu.c
@@ -162,11 +162,10 @@
  * checksum or something like that?
  */
 static void build_slot_path(char *buf, size_t bufsiz, size_t slot_id) {
-    char name_buf[40];
+    char name_buf[17];
 
     /* munge state file name */
-    strncpy(name_buf, rom.name, 40);
-    name_buf[16] = '\0';
+    strlcpy(name_buf, rom.name, sizeof(name_buf));
     munge_name(name_buf, strlen(name_buf));
 
     /* glom the whole mess together */
@@ -211,7 +210,7 @@
         /* build description buffer */
         memset(desc_buf, 0, 20);
         if (desc)
-            strncpy(desc_buf, desc, 20);
+            strlcpy(desc_buf, desc, 20);
 
         /* save state */
         write(fd, desc_buf, 20);
@@ -241,8 +240,7 @@
     if (!is_load)
         if (rb->kbd_input(desc_buf, 20) || !strlen(desc_buf))
         {
-            memset(desc_buf, 0, 20);
-            strncpy(desc_buf, "Untitled", 20);
+            strlcpy(desc_buf, "Untitled", 20);
         }
 
     /* load/save file */
diff --git a/apps/plugins/rockboy/rockmacros.h b/apps/plugins/rockboy/rockmacros.h
index 414b889..0fd13f6 100644
--- a/apps/plugins/rockboy/rockmacros.h
+++ b/apps/plugins/rockboy/rockmacros.h
@@ -67,7 +67,7 @@
 #define strcat(a,b)     rb->strcat((a),(b))
 #define memset(a,b,c)   rb->memset((a),(b),(c))
 #define strcpy(a,b)     rb->strcpy((a),(b))
-#define strncpy(a,b,c)  rb->strncpy((a),(b),(c))
+#define strlcpy(a,b,c)  rb->strlcpy((a),(b),(c))
 #define strlen(a)       rb->strlen((a))
 #define strcmp(a,b)     rb->strcmp((a),(b))
 #define strchr(a,b)     rb->strchr((a),(b))
diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c
index 20bebdd..5de6c14 100644
--- a/apps/plugins/rockpaint.c
+++ b/apps/plugins/rockpaint.c
@@ -686,7 +686,7 @@
                     if( selected < 0 || selected >= item_count )
                         break;
                     struct entry* e = &dc[indexes[selected]];
-                    rb->strncpy( bbuf_s, e->name, sizeof( bbuf_s ) );
+                    rb->strlcpy( bbuf_s, e->name, sizeof( bbuf_s ) );
                     if( !( e->attr & ATTR_DIRECTORY ) )
                     {
                         *tree = backup;
diff --git a/apps/plugins/shortcuts/shortcuts_common.c b/apps/plugins/shortcuts/shortcuts_common.c
index a06abd3..1a781b2 100644
--- a/apps/plugins/shortcuts/shortcuts_common.c
+++ b/apps/plugins/shortcuts/shortcuts_common.c
@@ -213,8 +213,7 @@
         DEBUGF("Bad entry: pathlen=%d, displen=%d\n", path_len, disp_len);
         return false;
     }
-    rb->strncpy(entry->path, path, path_len);
-    entry->path[path_len] = '\0';
+    rb->strlcpy(entry->path, path, path_len + 1);
     rb->strcpy(entry->disp, disp); /* Safe since we've checked the length */
     entry->explicit_disp = expl;
     return true;
@@ -295,15 +294,14 @@
         /* Too long name */
         return false;
     }
-    rb->strncpy(name, line, name_len);
-    name[name_len] = '\0';
+    rb->strlcpy(name, line, name_len + 1);
     
     val_len = rb->strlen(line) - name_len - NAME_VALUE_SEPARATOR_LEN;
     if (val_len >= valuesize) {
         /* Too long value */
         return false;
     }
-    rb->strncpy(value, sep+NAME_VALUE_SEPARATOR_LEN, val_len+1);
+    rb->strlcpy(value, sep+NAME_VALUE_SEPARATOR_LEN, val_len+1);
     return true;
 }
 
diff --git a/apps/plugins/sokoban.c b/apps/plugins/sokoban.c
index 8672249..bfd400b 100644
--- a/apps/plugins/sokoban.c
+++ b/apps/plugins/sokoban.c
@@ -689,7 +689,8 @@
 
 static void init_boards(void)
 {
-    rb->strncpy(buffered_boards.filename, SOKOBAN_LEVELS_FILE, MAX_PATH);
+    rb->strlcpy(buffered_boards.filename, SOKOBAN_LEVELS_FILE,
+                sizeof(buffered_boards.filename));
 
     current_info.level.index = 0;
     current_info.player.row = 0;
@@ -1026,8 +1027,8 @@
 
     /* Create dir if it doesn't exist */
     if ((loc = rb->strrchr(filename, '/')) != NULL) {
-        rb->strncpy(dirname, filename, loc - filename);
-        dirname[loc - filename] = '\0';
+        rb->strlcpy(dirname, filename, loc - filename + 1);
+
         if(!(dir = rb->opendir(dirname)))
             rb->mkdir(dirname);
         else
@@ -1082,7 +1083,9 @@
     if (rb->strncmp(buf, "Sokoban", 7) != 0) {
         rb->close(fd);
 
-        rb->strncpy(buffered_boards.filename, filename, MAX_PATH);
+        rb->strlcpy(buffered_boards.filename, filename,
+                    sizeof(buffered_boards.filename));
+
         if (!read_levels(true))
             return false;
 
diff --git a/apps/plugins/splitedit.c b/apps/plugins/splitedit.c
index 9f62b7a..a169a61 100644
--- a/apps/plugins/splitedit.c
+++ b/apps/plugins/splitedit.c
@@ -780,11 +780,11 @@
     bool part2_save = true;
 
     /* file name for left part */
-    rb->strncpy(part1_name, mp3->path, MAX_PATH);
+    rb->strlcpy(part1_name, mp3->path, MAX_PATH);
     generateFileName(part1_name, 1);
 
     /* file name for right part */
-    rb->strncpy(part2_name, mp3->path, MAX_PATH);
+    rb->strlcpy(part2_name, mp3->path, MAX_PATH);
     generateFileName(part2_name, 2);
 
     while (!exit_request)
diff --git a/apps/plugins/sudoku/sudoku.c b/apps/plugins/sudoku/sudoku.c
index f8a4385..77f6ca7 100644
--- a/apps/plugins/sudoku/sudoku.c
+++ b/apps/plugins/sudoku/sudoku.c
@@ -603,7 +603,7 @@
 {
     int r,c;
 
-    rb->strncpy(state->filename,GAME_FILE,MAX_PATH);
+    rb->strlcpy(state->filename,GAME_FILE,MAX_PATH);
     for (r=0;r<9;r++) {
         for (c=0;c<9;c++) {
             state->startboard[r][c]=default_game[r][c];
@@ -626,7 +626,7 @@
 {
     int r,c;
 
-    rb->strncpy(state->filename,GAME_FILE,MAX_PATH);
+    rb->strlcpy(state->filename,GAME_FILE,MAX_PATH);
     for (r=0;r<9;r++) {
         for (c=0;c<9;c++) {
             state->startboard[r][c]='0';
@@ -719,7 +719,7 @@
         return(false);
     }
 
-    rb->strncpy(state->filename,filename,MAX_PATH);
+    rb->strlcpy(state->filename,filename,MAX_PATH);
     n=rb->read(fd,buf,300);
     if (n <= 0) {
         return(false);
@@ -1111,7 +1111,7 @@
         rb->snprintf(str,sizeof(str),"Difficulty: %s",difficulty);
         display_board(state);
         rb->splash(HZ*3, str);
-        rb->strncpy(state->filename,GAME_FILE,MAX_PATH);
+        rb->strlcpy(state->filename,GAME_FILE,MAX_PATH);
     } else {
         display_board(&new_state);
         rb->splash(HZ*2, "Aborted");
diff --git a/apps/plugins/test_codec.c b/apps/plugins/test_codec.c
index a708ed7..c51fc40 100644
--- a/apps/plugins/test_codec.c
+++ b/apps/plugins/test_codec.c
@@ -451,7 +451,6 @@
 
     /* strings and memory */
     ci.strcpy = rb->strcpy;
-    ci.strncpy = rb->strncpy;
     ci.strlen = rb->strlen;
     ci.strcmp = rb->strcmp;
     ci.strcat = rb->strcat;
@@ -716,7 +715,7 @@
         /* Test all files in the same directory as the file selected by the
            user */
 
-        rb->strncpy(dirpath,parameter,sizeof(dirpath));
+        rb->strlcpy(dirpath,parameter,sizeof(dirpath));
         ch = rb->strrchr(dirpath,'/');
         ch[1]=0;
 
diff --git a/apps/plugins/text_editor.c b/apps/plugins/text_editor.c
index 703b330..617aeae 100644
--- a/apps/plugins/text_editor.c
+++ b/apps/plugins/text_editor.c
@@ -133,7 +133,7 @@
         rb->snprintf(buf , buf_len, "%s ...", b);
         b[buf_len-10] = t;
     }
-    else rb->strncpy(buf, b, buf_len);
+    else rb->strlcpy(buf, b, buf_len);
     return buf;
 }
 
diff --git a/apps/plugins/zxbox/snapshot.c b/apps/plugins/zxbox/snapshot.c
index d078ec7..9a68540 100644
--- a/apps/plugins/zxbox/snapshot.c
+++ b/apps/plugins/zxbox/snapshot.c
@@ -603,8 +603,7 @@
 {
   int type;
 
-  rb->strncpy(filenamebuf, name, MAXFILENAME-10);
-  filenamebuf[MAXFILENAME-10] = '\0';
+  rb->strlcpy(filenamebuf, name, MAXFILENAME-10 + 1);
 
   type = SN_Z80;
   if(check_ext(filenamebuf, "z80")) type = SN_Z80;
@@ -642,8 +641,7 @@
   int snsh;
   SNFILE snfil;
 
-  rb->strncpy(filenamebuf, name, MAXFILENAME-10);
-  filenamebuf[MAXFILENAME-10] = '\0';
+  rb->strlcpy(filenamebuf, name, MAXFILENAME-10 + 1);
 
   spcf_find_file_type(filenamebuf, &filetype, &type);
   if(type < 0) type = SN_Z80;
diff --git a/apps/plugins/zxbox/spconf.c b/apps/plugins/zxbox/spconf.c
index 5a14959..728f786 100644
--- a/apps/plugins/zxbox/spconf.c
+++ b/apps/plugins/zxbox/spconf.c
@@ -111,8 +111,7 @@
       
   file_type = extensions[ix].type;
   file_subtype = extensions[ix].subtype;
-  rb->strncpy(filenamebuf, parameter, MAXFILENAME - 10);
-  filenamebuf[MAXFILENAME-10] = '\0';
+  rb->strlcpy(filenamebuf, parameter, MAXFILENAME - 10 + 1);
   if(file_type < 0) file_subtype = -1;
   if(!spcf_find_file_type(filenamebuf, &file_type, &file_subtype))
     return;
diff --git a/apps/plugins/zxbox/sptape.c b/apps/plugins/zxbox/sptape.c
index f0e04de..21f962e 100644
--- a/apps/plugins/zxbox/sptape.c
+++ b/apps/plugins/zxbox/sptape.c
@@ -594,8 +594,7 @@
 {
   int filetype = FT_TAPEFILE;
 
-  rb->strncpy(tapename, name, MAXFILENAME-10);
-  tapename[MAXFILENAME-10] = '\0';
+  rb->strlcpy(tapename, name, MAXFILENAME-10 + 1);
 
   currseg = seg;
   tapetype = type;
diff --git a/apps/plugins/zxbox/tapefile.c b/apps/plugins/zxbox/tapefile.c
index 19f6aba..0e262aa 100644
--- a/apps/plugins/zxbox/tapefile.c
+++ b/apps/plugins/zxbox/tapefile.c
@@ -510,8 +510,7 @@
       int blen;
       rb->snprintf(seg_desc,DESC_LEN, "Begin Group: ");
       blen = (int) rb->strlen(seg_desc);
-      rb->strncpy(seg_desc+blen, (char *) rbuf, (unsigned) csp->len);
-      seg_desc[csp->len + blen] = '\0';
+      rb->strlcpy(seg_desc+blen, (char *) rbuf, (unsigned) csp->len + 1);
     }
     break;
 
@@ -618,8 +617,7 @@
       return 0;
     }
     csp->ptr += csp->len;
-    rb->strncpy(seg_desc, (char *) rbuf, (unsigned) csp->len);
-    seg_desc[csp->len] = '\0';
+    rb->strlcpy(seg_desc, (char *) rbuf, (unsigned) csp->len + 1);
     break;
 
   case 0x32:
diff --git a/apps/recorder/albumart.c b/apps/recorder/albumart.c
index 6bd2ada..a378c33 100644
--- a/apps/recorder/albumart.c
+++ b/apps/recorder/albumart.c
@@ -66,8 +66,7 @@
     }
 
     len = MIN(sep - fullpath + 1, buf_size - 1);
-    strncpy(buf, fullpath, len);
-    buf[len] = 0;
+    strlcpy(buf, fullpath, len + 1);
     return (sep + 1);
 }
 
@@ -266,7 +265,7 @@
     if (!found)
         return false;
 
-    strncpy(buf, path, buflen);
+    strlcpy(buf, path, buflen);
     logf("Album art found: %s", path);
     return true;
 }
diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c
index 8657aee..d1dc031 100644
--- a/apps/recorder/pcm_record.c
+++ b/apps/recorder/pcm_record.c
@@ -529,7 +529,7 @@
 /* queue another filename - will overwrite oldest one if full */
 static bool pcmrec_fnq_add_filename(const char *filename)
 {
-    strncpy(fn_queue + fnq_wr_pos, filename, MAX_PATH);
+    strlcpy(fn_queue + fnq_wr_pos, filename, MAX_PATH);
     fnq_wr_pos = FNQ_NEXT(fnq_wr_pos);
     
     if (fnq_rd_pos != fnq_wr_pos)
@@ -550,7 +550,7 @@
 
     pos = FNQ_PREV(fnq_wr_pos);
 
-    strncpy(fn_queue + pos, filename, MAX_PATH);
+    strlcpy(fn_queue + pos, filename, MAX_PATH);
 
     return true;
 } /* pcmrec_fnq_replace_tail */
@@ -562,7 +562,7 @@
         return false;
 
     if (filename)
-        strncpy(filename, fn_queue + fnq_rd_pos, MAX_PATH);
+        strlcpy(filename, fn_queue + fnq_rd_pos, MAX_PATH);
     
     fnq_rd_pos = FNQ_NEXT(fnq_rd_pos);
     return true;
@@ -976,7 +976,7 @@
     bool did_flush = false;                  /* did a flush occurr? */
 
     if (filename)
-        strncpy(path, filename, MAX_PATH);
+        strlcpy(path, filename, MAX_PATH);
     queue_reply(&pcmrec_queue, 0); /* We have all we need */
 
     data.pre_chunk = NULL;
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index 68c45c4..c5729ba 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -1138,7 +1138,7 @@
     }
     /* Temporary preset, loaded until player shuts down. */
     else if(filename[0] == '/') 
-        strncpy(filepreset, filename, sizeof(filepreset));
+        strlcpy(filepreset, filename, sizeof(filepreset));
     /* Preset from default directory. */
     else
         snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
@@ -1159,8 +1159,7 @@
                     {
                         struct fmstation * const fms = &presets[num_presets];
                         fms->frequency = f;
-                        strncpy(fms->name, name, MAX_FMPRESET_LEN);
-                        fms->name[MAX_FMPRESET_LEN] = '\0';
+                        strlcpy(fms->name, name, MAX_FMPRESET_LEN+1);
                         num_presets++;
                     }
                 }
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index d7ab9c7..0a890d0 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -964,7 +964,7 @@
             }
             else
             {
-                strncpy(buffer, str(LANG_RECORDING_FILENAME), buffer_len);
+                strlcpy(buffer, str(LANG_RECORDING_FILENAME), buffer_len);
             }
             break;
         }
diff --git a/apps/replaygain.c b/apps/replaygain.c
index b398afc..bcdbffe 100644
--- a/apps/replaygain.c
+++ b/apps/replaygain.c
@@ -218,8 +218,7 @@
         /* A few characters just isn't interesting... */
         if (len > 1)
         {
-            strncpy(buffer, value, len);
-            buffer[len] = 0;
+            strlcpy(buffer, value, len + 1);
             *p = buffer;
             return len + 1;
         }
diff --git a/apps/root_menu.c b/apps/root_menu.c
index 39d3fbe..15bc524 100644
--- a/apps/root_menu.c
+++ b/apps/root_menu.c
@@ -77,7 +77,7 @@
 static void rootmenu_track_changed_callback(void* param)
 {
     struct mp3entry *id3 = (struct mp3entry *)param;
-    strncpy(current_track_path, id3->path, MAX_PATH);
+    strlcpy(current_track_path, id3->path, MAX_PATH);
 }
 static int browser(void* param)
 {
@@ -202,7 +202,7 @@
 #endif
         case GO_TO_BROWSEPLUGINS:
             filter = SHOW_PLUGINS;
-            strncpy(folder, PLUGIN_DIR, MAX_PATH);
+            strlcpy(folder, PLUGIN_DIR, MAX_PATH);
         break;
     }
     ret_val = rockbox_browse(folder, filter);
diff --git a/apps/settings.c b/apps/settings.c
index e2f40a1..29360f1 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -246,8 +246,7 @@
             }
             else return false;
         }
-        strncpy(temp, start, end-start);
-        temp[end-start] = '\0';
+        strlcpy(temp, start, end-start+1);
         if (!strcmp(str, temp))
         {
             *out = count;
@@ -331,20 +330,18 @@
                                              settings[i].filename_setting->prefix,
                                              len))
                             {
-                                strncpy(storage,&value[len],MAX_PATH);
+                                strlcpy(storage, &value[len], MAX_PATH);
                             }
-                            else strncpy(storage,value,MAX_PATH);
+                            else strlcpy(storage, value, MAX_PATH);
                         }
-                        else strncpy(storage,value,MAX_PATH);
+                        else strlcpy(storage, value, MAX_PATH);
                         if (settings[i].filename_setting->suffix)
                         {
                             char *s = strcasestr(storage,settings[i].filename_setting->suffix);
                             if (s) *s = '\0';
                         }
-                        strncpy((char*)settings[i].setting,storage,
+                        strlcpy((char*)settings[i].setting, storage,
                                 settings[i].filename_setting->max_len);
-                        ((char*)settings[i].setting)
-                            [settings[i].filename_setting->max_len-1] = '\0';
                         break;
                     }
                 }
@@ -379,12 +376,11 @@
             if (value[count] == val)
             {
                 if (end == NULL)
-                    strncpy(buf, start, buf_len);
+                    strlcpy(buf, start, buf_len);
                 else 
                 {
                     int len = (buf_len > (end-start))? end-start: buf_len;
-                    strncpy(buf, start, len);
-                    buf[len] = '\0';
+                    strlcpy(buf, start, len+1);
                 }
                 return true;
             }
@@ -408,12 +404,11 @@
     }
     end = strchr(start,',');
     if (end == NULL)
-        strncpy(buf, start, buf_len);
+        strlcpy(buf, start, buf_len);
     else 
     {
         int len = (buf_len > (end-start))? end-start: buf_len;
-        strncpy(buf, start, len);
-        buf[len] = '\0';
+        strlcpy(buf, start, len+1);
     }
     return true;
 }
@@ -468,7 +463,7 @@
                     (char*)settings[i].setting,
                     settings[i].filename_setting->suffix);
             }
-            else strncpy(buf,(char*)settings[i].setting,
+            else strlcpy(buf,(char*)settings[i].setting,
                          settings[i].filename_setting->max_len);
             break;
     } /* switch () */
@@ -1011,7 +1006,7 @@
         break;
     case F_T_CHARPTR:
     case F_T_UCHARPTR:
-        strncpy((char*)var, setting->default_val.charptr,
+        strlcpy((char*)var, setting->default_val.charptr,
                 setting->filename_setting->max_len);
         break;
     }
@@ -1114,7 +1109,7 @@
 {
     (void)unit;
     const unsigned char *text = set_option_options[item].string;
-    strncpy(buf, P2STR(text), size);
+    strlcpy(buf, P2STR(text), size);
 }
 static int32_t set_option_get_talk_id(int value, int unit)
 {
@@ -1173,12 +1168,11 @@
     }
     if(ptr == fptr) extlen = 0;
 
-    if (strncasecmp(ROCKBOX_DIR, filename ,strlen(ROCKBOX_DIR)) ||
+    if (strncasecmp(ROCKBOX_DIR, filename, strlen(ROCKBOX_DIR)) ||
         (len-extlen > maxlen))
         return;
 
-    strncpy(setting, fptr, len-extlen);
-    setting[len-extlen]=0;
+    strlcpy(setting, fptr, len-extlen+1);
 
     settings_save();
 }
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 6187478..c39ab58 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -439,7 +439,7 @@
 static char* qs_write_to_cfg(void* setting, char*buf, int buf_len)
 {
     const struct settings_list *var = &settings[*(int*)setting];
-    strncpy(buf, var->cfg_name, buf_len);
+    strlcpy(buf, var->cfg_name, buf_len);
     return buf;
 }
 static bool qs_is_changed(void* setting, void* defaultval)
diff --git a/apps/tagcache.c b/apps/tagcache.c
index 07af9bf..4d4935a 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -706,7 +706,7 @@
         if (tag != tag_filename)
         {
             ep = (struct tagfile_entry *)&hdr->tags[tag][seek];
-            strncpy(buf, ep->tag_data, size-1);
+            strlcpy(buf, ep->tag_data, size);
             
             return true;
         }
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 691b227..5d61589 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -593,7 +593,7 @@
         menus[menu_count] = buffer_alloc(sizeof(struct menu_root));
         new_menu = menus[menu_count];
         memset(new_menu, 0, sizeof(struct menu_root));
-        strncpy(new_menu->id, buf, MAX_MENU_ID_SIZE-1);
+        strlcpy(new_menu->id, buf, MAX_MENU_ID_SIZE);
         entry->link = menu_count;
         ++menu_count;
         
@@ -839,7 +839,7 @@
                     menu = menus[menu_count];
                     ++menu_count;
                     memset(menu, 0, sizeof(struct menu_root));
-                    strncpy(menu->id, data, MAX_MENU_ID_SIZE-1);
+                    strlcpy(menu->id, data, MAX_MENU_ID_SIZE);
                 }
             
                 if (get_token_str(menu->title, sizeof(menu->title)) < 0)
@@ -1442,8 +1442,8 @@
                 csi = menu->items[seek]->si;
                 c->currextra = 0;
                 
-                strncpy(current_title[c->currextra], dptr->name, 
-                        sizeof(current_title[0]) - 1);
+                strlcpy(current_title[c->currextra], dptr->name, 
+                        sizeof(current_title[0]));
     
                 /* Read input as necessary. */
                 for (i = 0; i < csi->tagorder_count; i++)
@@ -1464,7 +1464,7 @@
                         if (source == source_current_path && id3)
                         {
                             char *e;
-                            strncpy(searchstring, id3->path, SEARCHSTR_SIZE);
+                            strlcpy(searchstring, id3->path, SEARCHSTR_SIZE);
                             e = strrchr(searchstring, '/');
                             if (e)
                                 *e = '\0';
@@ -1477,8 +1477,7 @@
                             char **src = (char**)((char*)id3 + offset);
                             if (*src)
                             {
-                                strncpy(searchstring, *src, SEARCHSTR_SIZE);
-                                searchstring[SEARCHSTR_SIZE-1] = '\0';
+                                strlcpy(searchstring, *src, SEARCHSTR_SIZE);
                             }
                         }
                         else
@@ -1528,8 +1527,8 @@
                 c->dirlevel--;
         
             /* Update the statusbar title */
-            strncpy(current_title[c->currextra], dptr->name, 
-                    sizeof(current_title[0]) - 1);
+            strlcpy(current_title[c->currextra], dptr->name, 
+                    sizeof(current_title[0]));
             break;
         
         default:
diff --git a/apps/talk.c b/apps/talk.c
index 73c2607..b2e25e1 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -533,7 +533,7 @@
 #endif /* CONFIG_CODEC == SWCODEC */
 
     talk_initialized = true;
-    strncpy((char *) last_lang, (char *)global_settings.lang_file,
+    strlcpy((char *)last_lang, (char *)global_settings.lang_file,
         MAX_FILENAME);
 
 #if CONFIG_CODEC == SWCODEC
@@ -755,7 +755,7 @@
     }
     char buf[MAX_PATH];
     /* Spell only the path component after the last slash */
-    strncpy(buf, path, MAX_PATH);
+    strlcpy(buf, path, sizeof(buf));
     if(strlen(buf) >1 && buf[strlen(buf)-1] == '/')
         /* strip trailing slash */
         buf[strlen(buf)-1] = '\0';
diff --git a/apps/tree.c b/apps/tree.c
index ef65c6d..576453a 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -505,7 +505,7 @@
         return tc.currdir;
     else if (size > 0)
     {
-        strncpy(buf, tc.currdir, size);
+        strlcpy(buf, tc.currdir, size);
         return buf;
     }
     else
@@ -924,7 +924,7 @@
             }
             else
             {
-                strncpy(current, LANG_DIR "/english.lng", sizeof(current));
+                strlcpy(current, LANG_DIR "/english.lng", sizeof(current));
             }
         }
         /* Center on currently loaded WPS */
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 50c57e3..8e1cef3 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -52,7 +52,7 @@
 common/strnatcmp.c
 common/strcpy.c
 common/strncmp.c
-common/strncpy.c
+common/strlcpy.c
 common/strrchr.c
 common/strtok.c
 common/strstr.c
diff --git a/firmware/common/dir_uncached.c b/firmware/common/dir_uncached.c
index c6af145..25677a0 100644
--- a/firmware/common/dir_uncached.c
+++ b/firmware/common/dir_uncached.c
@@ -58,8 +58,7 @@
             name = "/";           /* else this must be the root dir */
     }
 
-    strncpy(namecopy, name, MAX_PATH);
-    namecopy[MAX_PATH-1] = '\0';
+    strlcpy(namecopy, name, MAX_PATH);
 
     return volume;
 }
@@ -120,8 +119,7 @@
     volume = strip_volume(name, namecopy);
     pdir->volumecounter = 0;
 #else
-    strncpy(namecopy,name,sizeof(namecopy)); /* just copy */
-    namecopy[sizeof(namecopy)-1] = '\0';
+    strlcpy(namecopy, name, sizeof(namecopy)); /* just copy */
 #endif
 
     if ( fat_opendir(IF_MV2(volume,) &pdir->fatdir, 0, NULL) < 0 ) {
@@ -204,7 +202,7 @@
     if ( !entry.name[0] )
         return NULL;	
 
-    strncpy(theent->d_name, entry.name, sizeof( theent->d_name ) );
+    strlcpy(theent->d_name, entry.name, sizeof(theent->d_name));
     theent->attribute = entry.attr;
     theent->size = entry.filesize;
     theent->startcluster = entry.firstcluster;
@@ -230,8 +228,7 @@
         return -1;
     }
 
-    strncpy(namecopy,name,sizeof(namecopy));
-    namecopy[sizeof(namecopy)-1] = 0;
+    strlcpy(namecopy, name, sizeof(namecopy));
 
     /* Split the base name and the path */
     end = strrchr(namecopy, '/');
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c
index 01ed72a..e846d55 100644
--- a/firmware/common/dircache.c
+++ b/firmware/common/dircache.c
@@ -232,11 +232,11 @@
                 return -2;
             
             td->pathpos = strlen(dircache_cur_path);
-            strncpy(&dircache_cur_path[td->pathpos], "/", 
-                    sizeof(dircache_cur_path) - td->pathpos - 1);
+            strlcpy(&dircache_cur_path[td->pathpos], "/", 
+                    sizeof(dircache_cur_path) - td->pathpos);
 #ifdef SIMULATOR
-            strncpy(&dircache_cur_path[td->pathpos+1], td->entry->d_name, 
-                    sizeof(dircache_cur_path) - td->pathpos - 2);
+            strlcpy(&dircache_cur_path[td->pathpos+1], td->entry->d_name, 
+                    sizeof(dircache_cur_path) - td->pathpos - 1);
             
             td->newdir = opendir_uncached(dircache_cur_path);
             if (td->newdir == NULL)
@@ -245,8 +245,8 @@
                 return -3;
             }
 #else
-            strncpy(&dircache_cur_path[td->pathpos+1], td->entry.name,
-                    sizeof(dircache_cur_path) - td->pathpos - 2);
+            strlcpy(&dircache_cur_path[td->pathpos+1], td->entry.name,
+                    sizeof(dircache_cur_path) - td->pathpos - 1);
 
             td->newdir = *td->dir;
             if (fat_opendir(IF_MV2(volume,) &td->newdir,
@@ -399,7 +399,7 @@
     char* part;
     char* end;
 
-    strncpy(namecopy, path, sizeof(namecopy) - 1);
+    strlcpy(namecopy, path, sizeof(namecopy));
     cache_entry = dircache_root;
     before = NULL;
     
@@ -926,7 +926,7 @@
     char *new;
     long last_cache_size = dircache_size;
 
-    strncpy(basedir, path, sizeof(basedir)-1);
+    strlcpy(basedir, path, sizeof(basedir));
     new = strrchr(basedir, '/');
     if (new == NULL)
     {
@@ -997,8 +997,8 @@
     {
         if (fdbind_idx >= MAX_PENDING_BINDINGS)
             return ;
-        strncpy(fdbind_cache[fdbind_idx].path, path, 
-                sizeof(fdbind_cache[fdbind_idx].path)-1);
+        strlcpy(fdbind_cache[fdbind_idx].path, path, 
+                sizeof(fdbind_cache[fdbind_idx].path));
         fdbind_cache[fdbind_idx].fd = fd;
         fdbind_idx++;
         return ;
@@ -1141,7 +1141,7 @@
     /* Generate the absolute path for destination if necessary. */
     if (newpath[0] != '/')
     {
-        strncpy(absolute_path, oldpath, sizeof(absolute_path)-1);
+        strlcpy(absolute_path, oldpath, sizeof(absolute_path));
         p = strrchr(absolute_path, '/');
         if (!p)
         {
@@ -1151,7 +1151,7 @@
         }
         
         *p = '\0';
-        strncpy(p, absolute_path, sizeof(absolute_path)-1-strlen(p));
+        strlcpy(p, absolute_path, sizeof(absolute_path)-strlen(p));
         newpath = absolute_path;
     }
     
@@ -1246,7 +1246,7 @@
         if (regentry == NULL)
             return NULL;
 
-        strncpy(dir->secondary_entry.d_name, regentry->d_name, MAX_PATH-1);
+        strlcpy(dir->secondary_entry.d_name, regentry->d_name, MAX_PATH);
         dir->secondary_entry.size = regentry->size;
         dir->secondary_entry.startcluster = regentry->startcluster;
         dir->secondary_entry.attribute = regentry->attribute;
@@ -1268,7 +1268,7 @@
 
     dir->entry = ce->next;
 
-    strncpy(dir->secondary_entry.d_name, ce->d_name, MAX_PATH-1);
+    strlcpy(dir->secondary_entry.d_name, ce->d_name, MAX_PATH);
     /* Can't do `dir->secondary_entry = *ce`
        because that modifies the d_name pointer. */
     dir->secondary_entry.size = ce->size;
diff --git a/firmware/common/file.c b/firmware/common/file.c
index 7c01f03..3d7722f 100644
--- a/firmware/common/file.c
+++ b/firmware/common/file.c
@@ -132,8 +132,7 @@
     }
 #endif
 
-    strncpy(pathnamecopy,pathname,sizeof(pathnamecopy));
-    pathnamecopy[sizeof(pathnamecopy)-1] = 0;
+    strlcpy(pathnamecopy, pathname, sizeof(pathnamecopy));
 
     /* locate filename */
     name=strrchr(pathnamecopy+1,'/');
diff --git a/firmware/common/strlcpy.c b/firmware/common/strlcpy.c
new file mode 100644
index 0000000..ac30ef0
--- /dev/null
+++ b/firmware/common/strlcpy.c
@@ -0,0 +1,52 @@
+/*	$OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $	*/
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+	char *d = dst;
+	const char *s = src;
+	size_t n = siz;
+
+	/* Copy as many bytes as will fit */
+	if (n != 0) {
+		while (--n != 0) {
+			if ((*d++ = *s++) == '\0')
+				break;
+		}
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src */
+	if (n == 0) {
+		if (siz != 0)
+			*d = '\0';		/* NUL-terminate dst */
+		while (*s++)
+			;
+	}
+
+	return(s - src - 1);	/* count does not include NUL */
+}
+
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index 2ff4c61..a710593 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -1183,7 +1183,7 @@
             /* shortname entry */
             unsigned short date=0, time=0, tenth=0;
             LDEBUGF("Shortname entry: %s\n", shortname);
-            strncpy(entry + FATDIR_NAME, shortname, 11);
+            memcpy(entry + FATDIR_NAME, shortname, 11);
             entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
             entry[FATDIR_NTRES] = 0;
 
@@ -1271,7 +1271,7 @@
     /* The "." and ".." directory entries must not be long names */
     if(dotdir) {
         int i;
-        strncpy(shortname, name, 12);
+        strlcpy(shortname, name, 12);
         for(i = strlen(shortname); i < 12; i++)
             shortname[i] = ' ';
 
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index ef0865f..882bfa0 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -1152,7 +1152,7 @@
         }
 
         end = strchr(s->line, '\0');
-        strncpy(end, string, current_vp->width/2);
+        strlcpy(end, string, current_vp->width/2);
 
         s->vp = current_vp;
         s->y = y;
diff --git a/firmware/drivers/lcd-1bit-vert.c b/firmware/drivers/lcd-1bit-vert.c
index 5fb6524..f11fd6f 100644
--- a/firmware/drivers/lcd-1bit-vert.c
+++ b/firmware/drivers/lcd-1bit-vert.c
@@ -845,7 +845,7 @@
         }
 
         end = strchr(s->line, '\0');
-        strncpy(end, string, current_vp->width/2);
+        strlcpy(end, string, current_vp->width/2);
 
         s->vp = current_vp;
         s->y = y;
diff --git a/firmware/drivers/lcd-2bit-vert.c b/firmware/drivers/lcd-2bit-vert.c
index 801927e..57d27d2 100644
--- a/firmware/drivers/lcd-2bit-vert.c
+++ b/firmware/drivers/lcd-2bit-vert.c
@@ -1154,7 +1154,7 @@
         }
 
         end = strchr(s->line, '\0');
-        strncpy(end, (char *)string, current_vp->width/2);
+        strlcpy(end, (char *)string, current_vp->width/2);
 
         s->vp = current_vp;
         s->y = y;
diff --git a/firmware/drivers/lcd-2bit-vi.c b/firmware/drivers/lcd-2bit-vi.c
index 1c0a717..0a73f0d 100644
--- a/firmware/drivers/lcd-2bit-vi.c
+++ b/firmware/drivers/lcd-2bit-vi.c
@@ -1167,7 +1167,7 @@
         }
 
         end = strchr(s->line, '\0');
-        strncpy(end, (char *)string, current_vp->width/2);
+        strlcpy(end, (char *)string, current_vp->width/2);
 
         s->vp = current_vp;
         s->y = y;
diff --git a/firmware/drivers/lcd-charcell.c b/firmware/drivers/lcd-charcell.c
index ca58098..33337da 100644
--- a/firmware/drivers/lcd-charcell.c
+++ b/firmware/drivers/lcd-charcell.c
@@ -496,7 +496,7 @@
         }
 
         end = strchr(s->line, '\0');
-        strncpy(end, string, utf8seek(s->line, current_vp->width));
+        strlcpy(end, string, utf8seek(s->line, current_vp->width));
 
         s->vp = current_vp;
         s->y = y;
diff --git a/firmware/general.c b/firmware/general.c
index 14b2b55..6f7238e 100644
--- a/firmware/general.c
+++ b/firmware/general.c
@@ -110,7 +110,7 @@
     char fmtstring[12];
 
     if (buffer != path)
-        strncpy(buffer, path, MAX_PATH);
+        strlcpy(buffer, path, MAX_PATH);
 
     pathlen = strlen(buffer);
 
@@ -185,7 +185,7 @@
     last_tm = *tm;
 
     if (buffer != path)
-        strncpy(buffer, path, MAX_PATH);
+        strlcpy(buffer, path, MAX_PATH);
 
     pathlen = strlen(buffer);
     snprintf(buffer + pathlen, MAX_PATH - pathlen,
diff --git a/firmware/include/string.h b/firmware/include/string.h
index 32b86cd..6085c10 100644
--- a/firmware/include/string.h
+++ b/firmware/include/string.h
@@ -35,13 +35,14 @@
 size_t	 _EXFUN(strlen,(const char *));
 char 	*_EXFUN(strncat,(char *, const char *, size_t));
 int	 _EXFUN(strncmp,(const char *, const char *, size_t));
-char 	*_EXFUN(strncpy,(char *, const char *, size_t));
 char 	*_EXFUN(strpbrk,(const char *, const char *));
 char 	*_EXFUN(strrchr,(const char *, int));
 size_t	 _EXFUN(strspn,(const char *, const char *));
 char 	*_EXFUN(strstr,(const char *, const char *));
 char 	*_EXFUN(strcasestr,(const char *, const char *));
 
+size_t  strlcpy(char *dst, const char *src, size_t siz);
+
 #ifndef _REENT_ONLY
 char 	*_EXFUN(strtok,(char *, const char *));
 #endif
diff --git a/firmware/logf.c b/firmware/logf.c
index a704ad2..6e3e532 100644
--- a/firmware/logf.c
+++ b/firmware/logf.c
@@ -145,7 +145,7 @@
     while(len > MAX_LOGF_ENTRY)
     {
         ptr = logfbuffer[logfindex];
-        strncpy(ptr, buf + tlen, MAX_LOGF_ENTRY-1);
+        strlcpy(ptr, buf + tlen, MAX_LOGF_ENTRY);
         ptr[MAX_LOGF_ENTRY] = LOGF_TERMINATE_CONTINUE_LINE;
         logfindex++;
         check_logfindex();