Question

I am programming an ftp server using c++ and I need to be able to get all info about files in form of :

sent: drwxr-xr-x 1000 ubuntu ubuntu 4096 May 16 11:44 Package-Debug.bash

so I can send it to the client. I partially succeeded in doing that but I ran into a few problems. Here is a part of my code:

void Communication::LISTCommand() {
DIR *directory;
struct dirent *ent;
char path[100];
strcpy(path, this->path.c_str());  //this->path can be different from current working path

/*if (chdir(path) == -1) {
    perror("Error while changing the working directory ");
    close(clie_sock);
    exit(1);
}*/

directory = opendir(path);
struct tm* clock;
struct stat attrib;
struct passwd *pw;
struct group *gr;
string line;
char file_info[1000];

.....

while ((ent = readdir(directory)) != NULL) {
    line.clear();
    stat(ent->d_name, &attrib);

    clock = gmtime(&(attrib.st_mtime));
    pw = getpwuid(attrib.st_uid);
    gr = getgrgid(attrib.st_gid);
    if (S_ISDIR(attrib.st_mode))
        line.append(1, 'd');
    else line.append(1, '-');
    if (attrib.st_mode & S_IRUSR)
        line.append(1, 'r');
    else line.append(1, '-');
    if (attrib.st_mode & S_IWUSR)
        line.append(1, 'w');
    else line.append(1, '-');
    if (attrib.st_mode & S_IXUSR)
        line.append(1, 'x');
    else line.append(1, '-');
    if (attrib.st_mode & S_IRGRP)
        line.append(1, 'r');
    else line.append(1, '-');
    if (attrib.st_mode & S_IWGRP)
        line.append(1, 'w');
    else line.append(1, '-');
    if (attrib.st_mode & S_IXGRP)
        line.append(1, 'x');
    else line.append(1, '-');
    if (attrib.st_mode & S_IROTH)
        line.append(1, 'r');
    else line.append(1, '-');
    if (attrib.st_mode & S_IWOTH)
        line.append(1, 'w');
    else line.append(1, '-');
    if (attrib.st_mode & S_IXOTH)
        line.append("x ");
    else line.append("- ");

    sprintf(file_info, "%s%d %s %s %d %s %d %02d:%02d %s\r\n", line.c_str(), pw->pw_uid,
            pw->pw_name, gr->gr_name, (int) attrib.st_size, getMonth(clock->tm_mon).c_str(),
            clock->tm_mday, clock->tm_hour, clock->tm_min, ent->d_name);

    if (send(c_data_sock, file_info, strlen(file_info), 0) == -1) {
        perror("Error while writing ");
        close(clie_sock);
        exit(1);
    }

    cout << "sent: " << file_info << endl;
}

.....

}

When the path variable is different from the current working path, this code does not work. Valgrind says that there are many jumps that depend on unnitialized values etc. and the list of files contains wrong values - only file name and size are right. When I change the current working directory to the content of path variable, it does not report any errors but the file list still contains wrong info. i really have no clue what is wrong with my code so any help is much appreciated.

Was it helpful?

Solution

When you do

stat(ent->d_name, &attrib);

you should remember that ent->d_name contains only the file name, and not the full path. So if you want to list files in a directory different from the programs current directory you need to construct a full path to use.

The easiest solution is probably to do something like

std::string full_path = path;
full_path += '/';
full_path += ent->d_name;

if (stat(full_path.c_str(), &attrib) != -1)
{
    // Do your stuff here
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top