0

I have a C program where I use a recursive function that traverses a directory structure. It takes a time_t variable and creates a gmtime struct from it.

The recursive dir function is from How to recursively list directories in C on Linux?

void traversedir(time_t cutoff, const char* name, int indent)
{
    if (indent > 9)
        return;

    DIR* dir;
    struct dirent* entry;

    if (!(dir = opendir(name)))
        return;

    struct tm *t = gmtime(&cutoff);
    printf("%d-%d-%d %d:%d:%d (%lld)\n", (1900 + t->tm_year), (t->tm_mon + 1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, (long long) cutoff);
    sleep(1);  // only for debugging

    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_DIR) {
            char path[1024];
            if (entry->d_name[0] == '.' && !isValidNumber(entry->d_name))
                continue;
            snprintf(path, sizeof(path), "%s/%s", name, entry->d_name);

            ...

            traversedir(cutoff, path, indent + 2);
        }
    }
    closedir(dir);
}

void imageCleanup()
{
    time_t cutoff = (time(NULL) - (86400 * 10));
    do {
        printf("Cutoff: %lld\n", (long long) cutoff);
        traversedir(cutoff, "/path/to/dir", 0);
        sleep(2);
        cutoff += 3600;
    } while (!available_storage() && cutoff < time(NULL));
}

This is the output when running the program.

Cutoff: 1534245930
2018-8-14 11:25:30 (1534245930)
2018-8-24 11:25:31 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-24 11:25:33 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:35 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-24 11:25:38 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-24 11:25:43 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-24 11:25:52 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-24 11:25:54 (1534245930)
2018-8-14 11:25:55 (1534245930)
2018-8-24 11:25:56 (1534245930)
2018-8-14 11:25:30 (1534245930)
2018-8-24 11:25:58 (1534245930)

The time_t that the struct is converted from is in the parenthesis. It is consistently 1534245930 or August 14, 2018 11:25:30 AM, which is minus ten days at the execution of the program.

You can see that the conversion is pretty inconsistent. Several times the seconds follow the actual time at the time of execution. The day change a few times as well.

Anyone know or have an idea what could cause this? I have tried just making a simple loop that converts a static time_t without any problems, so I can only assume that it has something to

Kagemand Andersen
  • 1,470
  • 2
  • 16
  • 30

1 Answers1

2

Read carefully time(7) and gmtime(3).

Notice that gmtime is not reentrant since it returns the address of some static data. You want gmtime_r (since your traversedir function is recursive) and should use a local struct tm automatic variable.

so

struct tm mytm;
struct tm *t = gmtime_r(&cutoff, &mytm);

Then t would point to mytm on the call stack (not to some static data).

You also should use strftime(3) (again, with a large enough buffer declared as automatic variable, or some heap allocated buffer).

You might be also interested by nftw(3) and stat(2).

Read also How to debug small programs.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Ah, that makes sense then. I did read the man page for gmtime, but it doesn't explicit say that the function is not reentrant (it only talks about reentrace version in connection with ctime, which I probably should have assumed would be the same for gmtime in hindsight). Would probably also make more sense to just use nftw for dir traversal. Thanks! – Kagemand Andersen Aug 24 '18 at 12:34
  • But the man page do mention `gmtime_r` which would not be needed if `gmtime` was reentrant – Basile Starynkevitch Aug 24 '18 at 12:39