joncampbell123 / dosbox-x

DOSBox-X fork of the DOSBox project
GNU General Public License v2.0
2.81k stars 383 forks source link

Incorrect timestamp on IMGMOUNT disk #1015

Closed tomyun closed 5 years ago

tomyun commented 5 years ago

Describe the bug New files copied/created on IMGMOUNT-ed disk on PC-98 mode have incorrect timestamps.

I first found out this issue when copying some files out of IMGMOUNT-ed disk to regular MOUNT-ed disk. Further testing showed it also happens when creating a new file in IMGMOUNT-ed disk itself.

To Reproduce Steps to reproduce the behavior:

  1. See incorrect timestamp with the file copied to other disk.
    
    Z:\> imgmount c disk.hdi
    Z:\> mount d .
    Z:\> c:
    C:\> copy autoexec.bat d:
    C:\> dir d:

timestamp is "06-03-2095 4:47" when the original file was "05-07-2018 10:06"

2. See incorrect timestamp with a new file created.

C:> mkdir temp C:> cd temp C:\TEMP> echo abc > test.txt

timestamp is "00-00-1980 0:00"



**Expected behavior**
1. Copied files should have the same timestamps as original files.
2. New files should have timestamps reflecting the current time.

**Screenshots**
1. Copy case
![copy](https://user-images.githubusercontent.com/906626/52814767-ca897100-3051-11e9-8dcb-329d2713d3f1.png)
2. Create case
![create](https://user-images.githubusercontent.com/906626/52814775-cd846180-3051-11e9-928d-cdb285360538.png)

**Environment (please complete the following information):**
 - macOS 10.14.3
 - DOSBox-X 0.82.16 (HEAD: 6e5682fec9efc361040bbf982855f348da86a9bf) -- also happened on 0.82.15 release version
 - ```machine=pc98```

**Additional context**
N/A
joncampbell123 commented 5 years ago

Is this only in PC-98 mode or is this a problem with general DOS emulation?

Does this happen in the IBM PC/XT/AT mode?

tomyun commented 5 years ago

That's a good question. I didn't test it on IBM PC mode and a quick testing confirms that it also has a similar issue.

  1. A new file created in an IMGMOUNT-ed disk image has timestamp of 00-00-1980 0:00. Once it's copied out to a regular MOUNT point, its timestamp is shown as 30-11-2107 0:00 in dosbox-x. Interestingly, the same file seen from Finder has a different timestamp like Nov 30, 1979 at 12:00 AM.

  2. A file copied from MOUNT to IMGMOUNT shows 00-00-1980 0:00 on dosbox-x. Once its copied out to MOUNT back, its timestamp becomes 30-11-2107 0:00 as above.

joncampbell123 commented 5 years ago

Confirmed, on Linux, given a floppy image.

However copying it back to C: gives today's date.

joncampbell123 commented 5 years ago

Well, the first hint is that in src/dos/drive_fat.cpp, the function to create a new file uses memset() to create a new directory entry and then only fills in the attributes.

So a date/time field of 0x0000 0x0000 is Jan 1st, 1980 midnight as you'd expect.

joncampbell123 commented 5 years ago

I see an interesting problem here: The FAT driver is using the "created" file time/date fields that were added by Windows 95, not the original MS-DOS "modified" file time/date fields.

joncampbell123 commented 5 years ago

I made corrections to the FAT driver in the latest commit that corrects this issue.

Newly created files have the current date/time from the system.

If the DOS program writes to the file, the date/time is updated when the file is closed.

If a call is made to set the file date/time, then that time is written when the file is closed, so that COPY.EXE can preserve the file's date/time on the disk image.

Finally, the code was modified to use the MS-DOS "last modified" field that has existed since MS-DOS 1.0 rather than the "created" field that Windows 95 added.

tomyun commented 5 years ago

It's great that you figured it out! Testing the latest HEAD confirms now it mostly works, yet there seems to be still some edge cases that need attention. For example, one of my HDI images had a few files with original timestamp set to 1980-01-01 00:00, then these were copied to MOUNT volume with timestamp changed to the current time (i.e. 2019-02-16 17:42).

FYI, extracting the same files with NDC gave me correct timestamps of 1980-01-01 00:00.

joncampbell123 commented 5 years ago

I just booted an MS-DOS bootdisk and did a few tests with DEBUG.EXE.

My guess was correct in that opening the file read/write does nothing to the dirent, but writing the file updates the modified time.

I'm wondering if somehow the set time/date INT 21h call supercedes the date/time written to the dirent even if further writes are made to the file after the date/time call.

joncampbell123 commented 5 years ago

The latest commit allows the set time/date call to override the final date written to the dirent instead of forcing the current time after writing the file.

tomyun commented 5 years ago

The issue seems to remain with the latest commit (b6c13940eeb0cd64f98ea1425b603ca4375683ba). Timestamp 1980-01-01 00:00 still changed to the current time after files copied into MOUNT volume.

joncampbell123 commented 5 years ago

I'm not able to reproduce this here on Linux.

Here's how I test:

However according to your description this is an issue on Mac OS X, so I will pull out a mac system and try the same there.

joncampbell123 commented 5 years ago

Using touch, like this:

bash-4.3# touch -d '1980-01-01 00:00:00' AAA bash-4.3# ls -l AAA -rw-r--r-- 1 root root 14 Jan 1 1980 AAA bash-4.3# stat AAA File: AAA Size: 14 Blocks: 8 IO Block: 4096 regular file Device: 807h/2055d Inode: 32778918 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 1980-01-01 00:00:00.000000000 -0800 Modify: 1980-01-01 00:00:00.000000000 -0800 Change: 2019-02-21 00:38:45.811595397 -0800 Birth: - bash-4.3#

tomyun commented 5 years ago

Following the steps you did with touch, I was not able to reproduce the issue on macOS either. Maybe this issue is only specific to certain files stored in the image (particularly HDI?).

Here is a disk image contains the file (TEST in the root) that causes timestamp modification on copying. It's '1980-01-01 0:00' in IMGMOUNT then changed to '2107-11-30 0:00' in MOUNT. Confirmed that happens on both svga_s3 and pc98 machines.

test.hdi.zip

joncampbell123 commented 5 years ago

Before I look at the image, I just had a thought what might be the problem.

Does the file have a date of "Jan 1st, 1980" or does the date field in the FAT filesystem actually contain 0x0000, which is technically an invalid date since you can't say the 0th of the month and month -1 does not exist (January is struct tm.tm_mon == 0 and DOSBox-X's conversion ends up setting tm_mon == -1)?

joncampbell123 commented 5 years ago

I ask because it's possible mktime() fails to produce a correct result when DOSBox-X converts the DOS date to a date for use with mktime() and mktime() is probably returning -1 (invalid time) which then comes out as 2107-11-30 when used to set the file timestamp on the local system.

Or, it's possible mktime() succeeds but cannot handle struct tm.tm_mon == -1

joncampbell123 commented 5 years ago

By the way DOSBox and DOSBox-X prior to this fix always set the date/time fields in the FAT filesystem to zero. The code to set the timestamp was not there in the code before this fix.

joncampbell123 commented 5 years ago

Hm, looking at DIR, my hunch is correct:

jan198000

EDIT: 00-00-1980 could only happen if the date field is set to 0x0000. That's an invalid date and when given to mktime() produces an invalid date on the host.

joncampbell123 commented 5 years ago

So the fix to the issue is to range-check the date after conversion so that the date and time given to the file on the host filesystem is either the intended date/time or close enough if invalid.

joncampbell123 commented 5 years ago

Try the latest commit.

tomyun commented 5 years ago

My bad I had hard time distinguishing between 1980-00-00 and 1980-01-01. Anyways, confirmed 1980-00-00 got sanitized to 1980-01-01 with the latest commit. Now everything looks good to me. Thanks!