Is ctime always <= mtime?

前端 未结 5 1092
旧时难觅i
旧时难觅i 2021-02-14 13:38

When using os.stat() in Python, can I assume that st_ctime is always less then or equal to st_mtime? If not, why not?

The code will always run on Linux, but if there is

5条回答
  •  生来不讨喜
    2021-02-14 14:22

    You've got this the wrong way round! On Linux (or Mac, or any other Unix system), ctime will normally always be LATER than mtime, not earlier. Unlike Windows, where ctime is a file creation date and mtime is a file modification date, in Unix they're both modification dates, with the difference being that:

    • mtime gets updated whenever the file content changes
    • ctime gets updated whenever the file attributes change, including its mtime

    The man page for (at least some variants of) the stat utility refers to these respectively as the "Time of last data modification" and "Time of last status change".

    Thus whenever mtime gets updated, ctime also gets updated. The only mechanisms I know of by which you could ever get an mtime that is greater than the ctime are:

    • manually setting the mtime to be in the future using the utime or utimes system calls, or a utility that uses them like touch -d
    • writing to the disk in a way that bypasses the Linux file system API, or indeed bypasses the file system altogether, like:
      • writing to the disk from Windows
      • opening the disk's device file and writing to it
      • flipping bits on the disk with a laser, magnet, sonic screwdriver, or similar

    Since you've asked in the context of Python, let's make a simple Python tool that outputs the mtime and ctime of a given file to help us demonstrate this. We'll use the convenient os.path.getctime and os.path.getctime APIs in our script, but using the st_ctime and st_mtime properties of the result of a stat call would give exactly the same results:

    #!/usr/bin/python
    import os
    import sys
    
    target_filename = sys.argv[1]
    
    mtime = os.path.getmtime(target_filename)
    ctime = os.path.getctime(target_filename)
    
    print('mtime: %f ctime: %f' % (mtime, ctime))
    

    We can save that as pystat.py, make it executable, and experiment at our Unix shell:

    $ # Times are initially equal:
    $ touch foo
    $ ./pystat.py foo
    mtime: 1473979539.786961 ctime: 1473979539.786961
    $ 
    $ # It doesn't matter how I create the file:
    $ echo qwerty > bar
    $ ./pystat.py bar
    mtime: 1473979561.218961 ctime: 1473979561.218961
    $ 
    $ # 'touch'ing a created file updates both times:
    $ touch foo
    $ ./pystat.py foo
    mtime: 1473979584.642960 ctime: 1473979584.642960
    $ 
    $ touch bar
    $ ./pystat.py bar
    mtime: 1473979592.762960 ctime: 1473979592.762960
    $ 
    $ # Modifying an existing file updates both times:
    $ echo stuff >> foo
    $ ./pystat.py foo
    mtime: 1473979622.722959 ctime: 1473979622.722959
    $ 
    $ # Changing permissions ONLY updates the ctime:
    $ chmod 777 foo
    $ ./pystat.py foo
    mtime: 1473979622.722959 ctime: 1473979643.542958
    $ 
    $ # So does moving a file:
    $ mv bar baz
    $ ./pystat.py baz
    mtime: 1473979592.762960 ctime: 1473979659.586958
    $ 
    $ # Consequently, both files now have ctime > mtime
    $
    $ # However, we CAN manually set mtime in the future
    $ # and thereby cause ctime < mtime:
    $ touch --date="2041-01-01 12:34:56" foo
    $ ./pystat.py foo
    mtime: 2240656496.000000 ctime: 1473989678.258937
    

提交回复
热议问题