fopen, rename и дата создания файла
От: Maniacal Россия  
Дата: 20.02.24 09:27
Оценка:
система Win10, FS — NTFS
Наткнулся на проблему на ровном месте. Создаётся файл с помощью fopen с доступом "at" (можно и "wt"), через какое-то время закрывается и переименовывается в другой (типа, складывается архив). На месте него создаётся новый с именем, которое было у предыдущего до переименования. С датами последней записи, последнего доступа и последней модификации всё в порядке. А вот дата создания получается старая, такая же, какая была у предыдущего файла до переименования.
Re: fopen, rename и дата создания файла
От: Carc Россия https://vk.com/gosha_mazov
Дата: 20.02.24 09:38
Оценка:
Здравствуйте, Maniacal, Вы писали:

M>система Win10, FS — NTFS

M>Наткнулся на проблему на ровном месте. Создаётся файл с помощью fopen с доступом "at" (можно и "wt"), через какое-то время закрывается и переименовывается в другой (типа, складывается архив). На месте него создаётся новый с именем, которое было у предыдущего до переименования. С датами последней записи, последнего доступа и последней модификации всё в порядке. А вот дата создания получается старая, такая же, какая была у предыдущего файла до переименования.
Файл как переименовывается? Какой код?
Aml Pages Home
Re[2]: fopen, rename и дата создания файла
От: Maniacal Россия  
Дата: 20.02.24 09:45
Оценка:
Здравствуйте, Carc, Вы писали:

C>Файл как переименовывается? Какой код?


Сишная функция rename.
rename(acOldLogPathName, acNewLogFileName)

В FAR'е видно, что успешно исчезает исходный файл и появляется переименованный. В дебаге функция тоже возвращает 0 (нет ошибок).

UPD: VC++2015
Отредактировано 20.02.2024 9:55 Maniacal . Предыдущая версия .
Re[3]: fopen, rename и дата создания файла
От: Carc Россия https://vk.com/gosha_mazov
Дата: 20.02.24 10:43
Оценка:
Здравствуйте, Maniacal, Вы писали:

M>Здравствуйте, Carc, Вы писали:


C>>Файл как переименовывается? Какой код?


M>Сишная функция rename.

M>
M>rename(acOldLogPathName, acNewLogFileName)
M>

M>В FAR'е видно, что успешно исчезает исходный файл и появляется переименованный. В дебаге функция тоже возвращает 0 (нет ошибок).
M>UPD: VC++2015
А что сама C-шная rename вызывает?
В Винде есть несколько вариантов переименования\перемещения.
См. на MoveFileEx + флаг MOVEFILE_COPY_ALLOWED
Aml Pages Home
Re[4]: fopen, rename и дата создания файла
От: Maniacal Россия  
Дата: 20.02.24 11:26
Оценка:
Здравствуйте, Carc, Вы писали:

C>А что сама C-шная rename вызывает?

C>В Винде есть несколько вариантов переименования\перемещения.
C>См. на MoveFileEx + флаг MOVEFILE_COPY_ALLOWED

В disassembly дебаггер что-то не очень стремится нутро CRT показывать даже после включения загрузки символов, но тут проблема не в rename явно, а в fopen. Если создавать файл, который недавно был в файловой системе, то дата создания берётся от удалённого файла. Если хотя бы одну букву поменять в имени, то всё нормально. С костылями я смогу это обойти или через WinAPI тоже, напрямую задавая дату создания. Но коллеги не оценят, если догадаются заглянуть в код. Всё лицо разобьют себе фейспалмом. Не в тех годах я уже такими костылями заплатки в коде делать. Хотелось по-человечески. И главное разобраться за что. Косвенно где-то всплывают наводки, что это последствия зашитого в API функционала по сохранению даты создания файла при его копировании в другое место. Но тут и место то же, и файл не копируется, а создаётся новый.
Re[5]: fopen, rename и дата создания файла
От: Carc Россия https://vk.com/gosha_mazov
Дата: 20.02.24 11:47
Оценка:
Здравствуйте, Maniacal, Вы писали:

M>Здравствуйте, Carc, Вы писали:


C>>А что сама C-шная rename вызывает?

C>>В Винде есть несколько вариантов переименования\перемещения.
C>>См. на MoveFileEx + флаг MOVEFILE_COPY_ALLOWED

M>В disassembly дебаггер что-то не очень стремится нутро CRT показывать даже после включения загрузки символов, но тут проблема не в rename явно, а в fopen. Если создавать файл, который недавно был в файловой системе, то дата создания берётся от удалённого файла. Если хотя бы одну букву поменять в имени, то всё нормально. С костылями я смогу это обойти или через WinAPI тоже, напрямую задавая дату создания. Но коллеги не оценят, если догадаются заглянуть в код. Всё лицо разобьют себе фейспалмом. Не в тех годах я уже такими костылями заплатки в коде делать. Хотелось по-человечески. И главное разобраться за что. Косвенно где-то всплывают наводки, что это последствия зашитого в API функционала по сохранению даты создания файла при его копировании в другое место. Но тут и место то же, и файл не копируется, а создаётся новый.

Дык «другой бы спорил» ©
  • Ясен пень, что rename это в первую очередь некая абстракция, и не хочется от нее отступать. (кроссс-платформ!!?!)
  • А зачем дизасм? CRT как линкуется? Динамически или статически? Если статитечски, то можно посмотреть что получим в Map-файле!?!

    Как вариант, и именно чтоб капитал пробрести и невинность соблюсти, можно сначала писать не в только что удаленный файл (ну тот, который удалили\переименовали в архив или типа того), а в некий temp-файл (с каким-нить временным случайным именем).
    А когда запись заканчивается, и файл закрывается, то переименовывать его в то саоме, первое имя, которое удаляли\переименовыввали.

    Только сдается мне это все равно костыли. Чего там сама NTFS надумает, так оно и будет.
    Можно конечно еще посмотреть на SetFileTime, но опять же WIndows Specific...
  • Aml Pages Home
    Re[6]: fopen, rename и дата создания файла
    От: Maniacal Россия  
    Дата: 20.02.24 12:04
    Оценка:
    Здравствуйте, Carc, Вы писали:

    В общем, WinAPI CreateFile ведёт себя так же. Если файл с таким именем недавно был замечен в файловой системе, то при создании нового дата создания берётся от бывшего, хоть его и нет уже.
    Поправить получается кодом
    HANDLE h = CreateFileA(acOldLogPathName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    FILETIME ft;
    GetFileTime(h, NULL, &ft, NULL);
    SetFileTime(h, &ft, NULL, NULL);
    CloseHandle(h);

    Но у меня от такого кода глаза мироточить начинают. Но дата создания становится равна дате последнего доступа. Может комп перезагрузить, а то винда с таким аптаймом мне и похуже сюрпризы порой преподносила.
    Re[7]: fopen, rename и дата создания файла
    От: Carc Россия https://vk.com/gosha_mazov
    Дата: 20.02.24 12:23
    Оценка:
    Здравствуйте, Maniacal, Вы писали:

    M>В общем, WinAPI CreateFile ведёт себя так же. Если файл с таким именем недавно был замечен в файловой системе, то при создании нового дата создания берётся от бывшего, хоть его и нет уже.

    M>Поправить получается кодом
    M>
    M>HANDLE h = CreateFileA(acOldLogPathName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    M>FILETIME ft;
    M>GetFileTime(h, NULL, &ft, NULL);
    M>SetFileTime(h, &ft, NULL, NULL);
    M>CloseHandle(h);
    M>

    M>Но у меня от такого кода глаза мироточить начинают. Но дата создания становится равна дате последнего доступа. Может комп перезагрузить, а то винда с таким аптаймом мне и похуже сюрпризы порой преподносила.

    Ну дык я к тому и клоню, что все это NTFS-specific. И или уж что-то танце-бубнить в WinAPI, или уж полагаться на C-шную ширму renaме. Но только что там де факто за ширмой!?!

    PS: я бы все эти в CreateFile+SetFileTime в auto-стиль завернул, разве что.
    Чего нить типа такого псевдо-кода — думаю мысль понятна...
    class CMyFile(LPCTSTR lpszPathName) {//конструктор
         тут всякие CreateFile + проверка возвращенного HANDLE (файла)
    }
    ~CMyFile {//деструктор
       тут всякие SetFileTime
    }
    private: 
    void opeator new(size_t);//хрен вам! А не создание в куче. Только на стеке!
    }
    Aml Pages Home
    Re[7]: fopen, rename и дата создания файла
    От: Pavel Dvorkin Россия  
    Дата: 20.02.24 13:36
    Оценка:
    Здравствуйте, Maniacal, Вы писали:

    M>Здравствуйте, Carc, Вы писали:


    M>В общем, WinAPI CreateFile ведёт себя так же. Если файл с таким именем недавно был замечен в файловой системе, то при создании нового дата создания берётся от бывшего, хоть его и нет уже.


    Попробуй выполнить переименование с помощью

    https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexa

    с флагом MOVEFILE_WRITE_THROUGH
    With best regards
    Pavel Dvorkin
    Re: File System Tunneling
    От: m2user  
    Дата: 20.02.24 14:18
    Оценка: 199 (6)
    https://superuser.com/a/437161

    That is by design. If a file is created with the name of a just-deleted file, timestamps, attributes, and security are carried forward.

    Reason: Plenty of apps delete and recreate on saving, as opposed to truncating the existing file and writing the new contents. This feature fixes the (for the user unexpected) behaviour that security settings and all that suddenly disappear.

    Там в комментах ссылка на копию MS KB с настройками реестра этой feature.
    И кстати в ремарках GetFileTime тоже упоминается:
    https://learn.microsoft.com/en-au/windows/win32/api/fileapi/nf-fileapi-getfiletime#remarks

    If you rename or delete a file, then restore it shortly thereafter, Windows searches the cache for file information to restore. Cached information includes its short/long name pair and creation time.

    file system tunneling
    Re[8]: fopen, rename и дата создания файла
    От: Maniacal Россия  
    Дата: 20.02.24 14:20
    Оценка:
    Здравствуйте, Pavel Dvorkin, Вы писали:

    PD>Попробуй выполнить переименование с помощью


    PD>https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexa


    PD>с флагом MOVEFILE_WRITE_THROUGH


    при пошаговом выполнении код
    FILE* f = fopen("testfile.txt", "w");
    fclose(f);
    MoveFileExA("testfile.txt", "testfile.bak", MOVEFILE_WRITE_THROUGH);
    f = fopen("testfile.txt", "w");
    fclose(f);

    На втором fopen оставляет старую дату создания.
    Достаточно кода
    FILE* f = fopen("testfile.txt", "w");
    fclose(f);

    Просто запустить, потом грохнуть файл и снова запустить, чтобы убедиться, что дата создания не поменялась.
    Re: fopen, rename и дата создания файла
    От: watchmaker  
    Дата: 20.02.24 14:24
    Оценка: 208 (6)
    Здравствуйте, Maniacal, Вы писали:

    M>система Win10, FS — NTFS

    M>Наткнулся на проблему на ровном месте. Создаётся файл с помощью fopen с доступом "at" (можно и "wt"), через какое-то время закрывается и переименовывается в другой (типа, складывается архив). На месте него создаётся новый с именем, которое было у предыдущего до переименования. С датами последней записи, последнего доступа и последней модификации всё в порядке. А вот дата создания получается старая, такая же, какая была у предыдущего файла до переименования.

    Это для совместимости с MS-DOS сделано. Называется File Tunneling От языка и его runtime не зависит .

    https://gist.github.com/danzek/624d5c3aaa349f0e846281c75c2ec371 — начиная с раздела File System Tunneling идут ужасающие подробности как это работает и зачем сделано.
    Re: fopen, rename и дата создания файла
    От: wl. Россия  
    Дата: 25.02.24 15:00
    Оценка:
    Здравствуйте, Maniacal, Вы писали:

    M>система Win10, FS — NTFS

    M>Наткнулся на проблему на ровном месте. Создаётся файл с помощью fopen с доступом "at" (можно и "wt"), через какое-то время закрывается и переименовывается в другой (типа, складывается архив). На месте него создаётся новый с именем, которое было у предыдущего до переименования. С датами последней записи, последнего доступа и последней модификации всё в порядке. А вот дата создания получается старая, такая же, какая была у предыдущего файла до переименования.

    создай файл с рандомным именем, а потом сразу переименуй его в тот, куда будешь записывать свои логи
    Re[2]: fopen, rename и дата создания файла
    От: Maniacal Россия  
    Дата: 28.02.24 09:31
    Оценка:
    Здравствуйте, wl., Вы писали:

    wl.>создай файл с рандомным именем, а потом сразу переименуй его в тот, куда будешь записывать свои логи


    Был и такой вариант обхода проблемы. Всё равно не красиво. Решил насильной установкой даты создания через WinAPI. Всё равно кросс-платформенность в данном конкретном проекте не требуется.
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.