touchall script

the touch command under is useful, but not found under windows system. So just write one by hand:

The critical API is SetFileTime.

SetFileTime(h, file_time, file_time, file_time);

This touchall script find all dirs and files under specify path recursively. and change all file-time (ctime/mtime/atime) to now.

Sources …..

/* vim: set fileencoding=utf-8:
 *
 *                   GNU GENERAL PUBLIC LICENSE
 *                       Version 2, June 1991
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 * 
 * g++ --static touchall.cpp
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>

#include <windows.h>

#include <iostream>
#include <cstdlib>
#include <list>
#include <algorithm>

#define VERSION "0.1.0"

static const char* errmsg(DWORD errid)
{
    static char message[8196];

    FormatMessage(
            FORMAT_MESSAGE_FROM_SYSTEM,
            NULL, 
            errid,
            MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
            message,
            sizeof(message),
            NULL);

    return message;
}

void print_time(SYSTEMTIME* sys_utc)
{
    SYSTEMTIME sys_local;
    SystemTimeToTzSpecificLocalTime(NULL, sys_utc, &sys_local);
    printf("%04d-%02d-%02d %02d:%02d:%02d",
            sys_local.wYear, sys_local.wMonth, sys_local.wDay,
            sys_local.wHour, sys_local.wMinute, sys_local.wSecond);
}

static FILETIME _timestamp;

int touch(const char* fn, FILETIME* file_time)
{
    HANDLE h;
    DWORD attributes;
    DWORD attributes_tmp;
    DWORD errid;

    ////////////////////////////////////////////////////////
    //
    //  check file writable
    //
    attributes = GetFileAttributes(fn);
    if (attributes == INVALID_FILE_ATTRIBUTES) {
        errid = GetLastError();
        printf("Error: GetFileAttributes fail, %d, %s\n", errid, errmsg(errid));
        return -1;
    }

    attributes_tmp = attributes;
    if (attributes & FILE_ATTRIBUTE_READONLY) {
        //printf("Warning: Read-only! \"%s\"\n", fn);
        attributes_tmp &= ~FILE_ATTRIBUTE_READONLY;
    }

    if (attributes_tmp != attributes) {
        SetFileAttributes(fn, attributes_tmp);
    }

    ////////////////////////////////////////////////////////
    DWORD flag;
    if (attributes & FILE_ATTRIBUTE_DIRECTORY) {
        flag = FILE_FLAG_BACKUP_SEMANTICS;
    } else {
        flag = FILE_ATTRIBUTE_NORMAL;
    }

    h = CreateFile(
            fn,
            GENERIC_READ|GENERIC_WRITE,
            FILE_SHARE_READ|FILE_SHARE_WRITE,
            NULL, 
            OPEN_EXISTING,
            flag,
            NULL);

    if (h == INVALID_HANDLE_VALUE) {
        errid = GetLastError();
        printf("Error: Open fail, %d, %s\n", errid, errmsg(errid));
        return -1;
    }

    if (!SetFileTime(h, file_time, file_time, file_time)) {
        errid = GetLastError();
        printf("Error: SetFileTime fail, %d, %s\n", errid, errmsg(errid));
        CloseHandle(h);
        return -1;
    }

    if (attributes_tmp != attributes) {
        SetFileAttributes(fn, attributes);
    }

    CloseHandle(h);
    return 0;
}


int main(int argc, char* argv[])
{
    HANDLE h;
    DWORD errid;
    WIN32_FIND_DATA file_data;

    std::string root;
    std::list<std::string> l_dirs;
    std::list<std::string> l_files;
    std::list<std::string> l_dir_fifo;
    char ch;

    ////////////////////////////////////////////////////////
    //
    //  argument check and prepare
    //
    if (argc != 2) {
        printf("Usage: %s dirpath\n", argv[0]);
        printf("Version: %s\n", VERSION);
        printf("Build: %s %s\n", __DATE__, __TIME__);
        return 0;
    }

    root = argv[1];
    ch = root.back();
    if ((ch == '/') || (ch == '\\')) {
        root.erase(root.size()-1, sizeof(char));
    }

    l_dir_fifo.push_back(root);

    ////////////////////////////////////////////////////////
    //
    //  find dirs and files recursively
    //
    while (l_dir_fifo.size() > 0) {
        ////////////////////////////////////////////////////
        //
        //  create pattern
        //
        std::string dirname = l_dir_fifo.front();
        std::string prefix;
        std::string pattern;
        l_dir_fifo.pop_front();

        ch = dirname.back();
        if ((ch == '/') || (ch == '\\')) {
            dirname.erase(0, sizeof(char));
        }
        prefix = dirname;
        pattern= prefix + "/*";

        ////////////////////////////////////////////////////
        //
        //  list all items in same depth (same prefix).
        //
        h = FindFirstFile(pattern.c_str(), &file_data);
        if (h == INVALID_HANDLE_VALUE) {
            errid = GetLastError();
            printf("Error: FindFirstFile(\"%s\") fail, %d, %s\r\n",
                    dirname.c_str(), errid, errmsg(errid));
            break;
        }

        while (1) {
            std::string name;
            name = prefix + "/";
            name = name + file_data.cFileName;

            if (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                if (file_data.cFileName[0] == '$') {
                } else if (file_data.cFileName[0] == '~') {
                } else if (strcmp(file_data.cFileName, ".") == 0) {
                } else if (strcmp(file_data.cFileName, "..") == 0) {
                } else if (strcmp(file_data.cFileName, "System Volume Information") == 0) {
                } else {
                    l_dirs.push_back(name);
                    l_dir_fifo.push_back(name);
                }
            } else {
                l_files.push_back(name);
            }

            if (!FindNextFile(h, &file_data)) {
                break;
            }
        }

        CloseHandle(h);
    }

    ////////////////////////////////////////////////////////
    //
    //  create UTC file time
    //
    SYSTEMTIME sys_utc; // UTC
    GetSystemTime(&sys_utc);
    SystemTimeToFileTime(&sys_utc, &_timestamp);

    ////////////////////////////////////////////////////////
    //
    //  touch all dirs
    //
    std::for_each(l_dirs.begin(), l_dirs.end(),
        [](const std::string& name) {
            printf("DIR %s\n", name.c_str());
            touch(name.c_str(), &_timestamp);
        }
    );


    ////////////////////////////////////////////////////////
    //
    //  touch all files
    //
    std::for_each(l_files.begin(), l_files.end(),
        [](const std::string& name) {
            printf("FILE %s\n", name.c_str());
            touch(name.c_str(), &_timestamp);
        }
    );

    ////////////////////////////////////////////////////////
    //
    //  summary
    //
    if ((errid == 0) | (errid == ERROR_SUCCESS)) {
        int nr_dirs = l_dirs.size();
        int nr_files= l_files.size();

        if ((nr_dirs > 0) || (nr_files > 0)) {
            printf("\n");
            printf("<");
            print_time(&sys_utc);
            printf(">\n");

            if (nr_dirs > 0) {
                printf(" %d dirs\n", nr_dirs);
            }
            if (nr_files > 0) {
                printf(" %d files\n", nr_files);
            }

        } else {
            printf("\"%s\" is empty\n", root.c_str());
        }
    }

    return 0;
}

This entry was posted in Others and tagged , , . Bookmark the permalink.