strncpy help (long)

F

fybar

Hi, I am in the progress of writing a program that will read in the
contents of a directory and then do some stuff to some of the files. So
far I am getting the contents of the directory but I get a strange
result from one file. Here is my program, feel free to critique:

#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>


void main(int argc, char *argv[])
{
int i;
int j;
int array_size;
DIR *dirp;
struct dirent *direntp;
char filename[NAME_MAX];

/* print usage */
switch(argc) {
case 1:
printf("Usage: %s path\n\n", argv[0]);
exit(1);
break;
/* print out dir contents */
default :
for ( i=1; i < argc; i++){
dirp = opendir( argv );
printf("This is the dir %s.\n\n", argv);
while ( (direntp = readdir( dirp )) != NULL )
{
printf( "1. strlen from raw {%d}\n", strlen(direntp->d_name) );
printf( "2. raw from pointer {%s}\n",direntp->d_name );
strncpy(filename,direntp->d_name,strlen(direntp->d_name));
array_size=strlen(filename);
printf("This is the string length %d\n", array_size);
if ( strncmp( filename, "r",1 )==0 ){
printf( "3. Modified string {%s}\n",filename );
}
for ( j=1; j <= array_size; j++ ) {
filename[j]=0;
}
}
}
break;
}

closedir( dirp );
exit(0);
}
I call the program:
myprog /usr/data/r*

I get data like this:
This is the dir /usr/data/rui19.

1. strlen from raw {1}
2. raw from pointer {.}
This is the string length 6
1. strlen from raw {2}
2. raw from pointer {..}
This is the string length 2
1. strlen from raw {14}
2. raw from pointer {rui19.ils.0001}
This is the string length 14
3. Modified string {rui19.ils.0001}

However one file gives me this:

1. strlen from raw {18}
2. raw from pointer {rui22.ils.0052.bak}
This is the string length 22
3. Modified string {rui22.ils.0052.baM-@M-^?^C}

What is that on the end of the file name? This file was created from a
winder's version of edt, vms guy just won't let go, and saved over a
Samba share to a Tru64 box. I don't know if some characters were
concatenated to the end of the filename, but an ls shows the filename
properly. Is there something in the filename or is my program to blame?
I have not tried removing or renaming the file as I don't want to lose
this behaviour until I undestand it. The odd part is that if I print
out the name directly from the dirent struct I don't see a problem, I
only see it after the strncpy. This is the only file that does this.

Also, I created the array_size variable because this wouldn't work.
What is wrong with this statement?

for ( j=1; j <= strlen(filename); j++

Thanks!

fyb
 
M

Merrill & Michele

"fybar" <[email protected]> wrote > Hi, I am in the progress of
writing a program that will read in the
contents of a directory and then do some stuff to some of the files. So
far I am getting the contents of the directory but I get a strange
result from one file. Here is my program, feel free to critique:

#include <sys/types.h>
#include <dirent.h>
[snip]

I don't believe that these are header files that are kosher around here. I
wouldn't know unix from a boomerang (haven't used either). Maybe other
people can point you in the right direction. MPJ
 
J

Jonathan Adams

What is that on the end of the file name? This file was created from a
winder's version of edt, vms guy just won't let go, and saved over a
Samba share to a Tru64 box. I don't know if some characters were
concatenated to the end of the filename, but an ls shows the filename
properly. Is there something in the filename or is my program to blame?
I have not tried removing or renaming the file as I don't want to lose
this behaviour until I undestand it. The odd part is that if I print
out the name directly from the dirent struct I don't see a problem, I
only see it after the strncpy. This is the only file that does this.

You don't want strncpy() -- you want strcpy(). strncpy() does not
'\0'-terminate the string if it's third argument is <= the length of
the second argument. You've carefully made sure that it is ==.

- jonathan
 
D

dandelion

You don't want strncpy() -- you want strcpy(). strncpy() does not
'\0'-terminate the string if it's third argument is <= the length of
the second argument. You've carefully made sure that it is ==.

In that case strcpy will cause a buffer-overrun and allow hostile code to be
executed. I'd suggest using strncpy and checking the results.
 
J

Jonathan Adams

"dandelion said:
In that case strcpy will cause a buffer-overrun and allow hostile code to be
executed. I'd suggest using strncpy and checking the results.

His use of strncpy() is wrong, and checking the results would not help
him:

....
char filename[NAME_MAX];
....
strncpy(filename,direntp->d_name,strlen(direntp->d_name));
....

It is just as susceptible to buffer overflows as strcpy() would be.
What the OP actually wants is strlcpy():

char filename[NAME_MAX];
....
if (strlcpy(filename, direntp->d_name, sizeof (filename)) >=
sizeof(filename)) {
/* overflow */
}
....

size_t
strlcpy(char *out, const char *in, size_t len)
{
size_t ret = strlen(in);

if (ret < len) {
(void) strcpy(out, in);
} else {
(void) strncpy(out, in, len - 1);
out[len - 1] = '\0';
}
return (ret);
}

(yes, there are more efficient ways of writing strlcpy())

Cheers,
- jonathan
 
D

dandelion

Jonathan Adams said:
His use of strncpy() is wrong, and checking the results would not help
him:

...


Ok. I checked and you're right.

char filename[NAME_MAX];
...
strncpy(filename,direntp->d_name,strlen(direntp->d_name));


strncpy(filename, direntp->d_name, NAME_MAX);

And check the results.

(yes, there are more efficient ways of writing strlcpy())

I'm glad you noticed.

In fact, there aren't many sensible ways to implement it less efficient
without deliberately trying.

Cheers,

dandelion.
 
D

dandelion

size_t
strlcpy(char *out, const char *in, size_t len)
{
size_t ret = strlen(in);

if (ret < len) {
(void) strcpy(out, in);
} else {
(void) strncpy(out, in, len - 1);
out[len - 1] = '\0';
}
return (ret);
}

(yes, there are more efficient ways of writing strlcpy())

size_t
strlcpy(char *dst, const char *src, size_t len)
{
size_t cnt = 0;
len--;

while('\0' != src[cnt] && cnt < len)
{
dst[cnt] = src[cnt];
cnt++;
}

out[cnt] = '\0';
return cnt;
}

Cheers,
dandelion.

PS. The above is not tested and may contain errors.
 
J

Jonathan Adams

"dandelion said:
size_t
strlcpy(char *out, const char *in, size_t len)
{
size_t ret = strlen(in);

if (ret < len) {
(void) strcpy(out, in);
} else {
(void) strncpy(out, in, len - 1);
out[len - 1] = '\0';
}
return (ret);
}

(yes, there are more efficient ways of writing strlcpy())

size_t
strlcpy(char *dst, const char *src, size_t len)
{
size_t cnt = 0;
len--;

while('\0' != src[cnt] && cnt < len)
{
dst[cnt] = src[cnt];
cnt++;
}

out[cnt] = '\0';
return cnt;
}

Cheers,
dandelion.

PS. The above is not tested and may contain errors.

For example, it doesn't match the openbsd definition:

The strlcpy and strlcat functions return the total length of
the string they tried to create. For strlcpy that means the
length of src.

- jonathan
 
D

dandelion

Jonathan Adams said:
dandelion said:
size_t
strlcpy(char *out, const char *in, size_t len)
{
size_t ret = strlen(in);

if (ret < len) {
(void) strcpy(out, in);
} else {
(void) strncpy(out, in, len - 1);
out[len - 1] = '\0';
}
return (ret);
}

(yes, there are more efficient ways of writing strlcpy())

size_t
strlcpy(char *dst, const char *src, size_t len)
{
size_t cnt = 0;
len--;

while('\0' != src[cnt] && cnt < len)
{
dst[cnt] = src[cnt];
cnt++;
}

out[cnt] = '\0';
return cnt;
}

Cheers,
dandelion.

PS. The above is not tested and may contain errors.

For example, it doesn't match the openbsd definition:

I'm no OpenBSD user, so don't expect me to know their standards.
The strlcpy and strlcat functions return the total length of
the string they tried to create. For strlcpy that means the
length of src.

In this case I would say the OpenBSD definition sucks, since the src string
is not guaranteed *) to be zero teriminated, in which case strlen will
return a preposterous value if you do not SIGSEGV with an out-of-bounds
pointer (you code).

And if it is... Easy... Add a small extra loop counting till the '\0' comes
home.

I still prefer strncpy.

*) it's a library function after all. I know that *in this case* it's
guaranteed.
 
C

CBFalconer

Jonathan said:
.... snip ...

(yes, there are more efficient ways of writing strlcpy())

For example (full file <http://cbfalconer.home.att.net/download>):

#include "strlcpy.h"

/* NOTE: these routines are deliberately designed to
not require any assistance from the standard
libraries. This makes them more useful in any
embedded systems that must minimize the load size.

Public domain, by C.B. Falconer
bug reports to mailto:[email protected]
*/

/* ---------------------- */

size_t strlcpy(char *dst, const char *src, size_t sz)
{
const char *start = src;

if (src && sz--) {
while ((*dst++ = *src))
if (sz--) src++;
else {
*(--dst) = '\0';
break;
}
}
if (src) {
while (*src++) continue;
return src - start - 1;
}
else if (sz) *dst = '\0';
return 0;
} /* strlcpy */

/* ---------------------- */

size_t strlcat(char *dst, const char *src, size_t sz)
{
char *start = dst;

while (*dst++) /* assumes sz >= strlen(dst) */
if (sz) sz--; /* i.e. well formed string */
dst--;
return dst - start + strlcpy(dst, src, sz);
} /* strlcat */
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top