Skip to content

Commit 85de7ac

Browse files
committed
Fix (FileStream): Fix truncating file on Unix
1 parent de0660f commit 85de7ac

File tree

4 files changed

+25
-21
lines changed

4 files changed

+25
-21
lines changed

libraries/libim/io/impl/filestream.cpp

+18-14
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,6 @@ struct FileStream::FileStreamImpl
6969
mode(mode),
7070
filePath(std::move(fp))
7171
{
72-
if(truncate && mode != Read) {
73-
std::filesystem::remove(filePath);
74-
}
75-
7672
auto flags = [&]()
7773
{
7874
switch (mode)
@@ -85,12 +81,11 @@ struct FileStream::FileStreamImpl
8581
return static_cast<DWORD>(-1);
8682
#else
8783
case Read: return O_RDONLY;
88-
case Write: return O_WRONLY | O_CREAT | O_TRUNC;
89-
case ReadWrite: return O_RDWR | O_CREAT | O_TRUNC;
84+
case Write: return O_WRONLY | O_CREAT;
85+
case ReadWrite: return O_RDWR | O_CREAT;
9086
default:
9187
return -1;
9288
#endif
93-
9489
}
9590
}();
9691

@@ -105,33 +100,38 @@ struct FileStream::FileStreamImpl
105100
to flag param of function CreateFileX.
106101
See: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-flushfilebuffers#remarks
107102
*/
103+
DWORD dwCreationDisposition = flags == GENERIC_READ ? OPEN_EXISTING : OPEN_ALWAYS;
108104
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
109105
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
110106
std::wstring wPath = converter.from_bytes(filePath.c_str());
111-
112107
hFile = CreateFile2(
113108
wPath.c_str(),
114109
flags,
115110
FILE_SHARE_READ,
116-
(flags == GENERIC_READ ? OPEN_EXISTING : OPEN_ALWAYS),
111+
dwCreationDisposition,
117112
nullptr
118113
);
119114
#else
120115
hFile = CreateFileA(
121116
filePath.c_str(),
122117
flags,
123118
FILE_SHARE_READ,
124-
NULL,
125-
(flags == GENERIC_READ ? OPEN_EXISTING : OPEN_ALWAYS),
119+
nullptr,
120+
dwCreationDisposition,
126121
FILE_ATTRIBUTE_NORMAL,
127-
NULL
122+
nullptr
128123
);
129124
#endif
130125

131126
if (hFile == INVALID_HANDLE_VALUE) {
132127
throw FileStreamError(getLastErrorAsString());
133128
}
134129

130+
/* Truncate file if writable */
131+
if ((flags & GENERIC_WRITE) && truncate && !SetEndOfFile(hFile)) {
132+
throw FileStreamError(getLastErrorAsString());
133+
}
134+
135135
/* Get file size */
136136
LARGE_INTEGER lSize {{0, 0}};
137137
if(!GetFileSizeEx(hFile, &lSize)) {
@@ -144,8 +144,12 @@ struct FileStream::FileStreamImpl
144144
fileSize = lSize.LowPart;
145145
#endif
146146

147-
#else // Not Win
147+
#else // Unix
148148
/* Open file */
149+
if (mode != Read && truncate) {
150+
flags |= O_TRUNC;
151+
}
152+
149153
fd = open(filePath.c_str(), flags, (mode_t)0600);
150154
if (fd == -1) {
151155
throw FileStreamError(strerror(errno));
@@ -257,7 +261,7 @@ struct FileStream::FileStreamImpl
257261
#ifdef OS_WINDOWS
258262
LARGE_INTEGER li;
259263
li.QuadPart = offset;
260-
li.LowPart = SetFilePointer(hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
264+
li.LowPart = SetFilePointer(hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
261265
if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
262266
#else
263267
auto off = lseek(fd, offset, SEEK_SET);

programs/cndtool/main.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ std::size_t extractAnimations(const InputStream& istream, const std::string& out
619619
}
620620

621621
std::string keyFilePath(keyDir + "/" + key.name());
622-
OutputFileStream ofs(std::move(keyFilePath));
622+
OutputFileStream ofs(std::move(keyFilePath), /*truncate=*/true);
623623
key.serialize(TextResourceWriter(ofs), keyHeaderComment);
624624
}
625625

@@ -668,7 +668,7 @@ std::size_t extractMaterials(const InputStream& istream, const std::string& outD
668668
}
669669

670670
std::string matFilePath(matDir + "/" + mat.name());
671-
mat.serialize(OutputFileStream(std::move(matFilePath)));
671+
mat.serialize(OutputFileStream(std::move(matFilePath), /*truncate=*/true));
672672

673673
if(opt.verboseOutput)
674674
{
@@ -759,14 +759,14 @@ std::size_t extractSounds(const InputStream& istream, const std::string& outDir,
759759
std::cout << "Extracting sound: " << s.name() << std::endl;
760760
}
761761

762-
OutputFileStream ofs(outPath.append(s.name()));
762+
OutputFileStream ofs(outPath.append(s.name()), /*truncate=*/true);
763763
s.serialize(ofs, Sound::SerializeFormat::IndyWV);
764764
outPath = outPath.parent_path();
765765

766766
/* Save in WAV format */
767767
if(opt.sound.convertToWav)
768768
{
769-
OutputFileStream ofs(wavDir.append(s.name()));
769+
OutputFileStream ofs(wavDir.append(s.name()), /*truncate=*/true);
770770
s.serialize(ofs, Sound::SerializeFormat::WAV);
771771
wavDir = wavDir.parent_path();
772772
}

programs/cndtool/patch.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ using namespace libim::utils;
2525

2626
/* Open new output cnd file */
2727
const std::string patchedCndFile = cndFile + ".patched";
28-
OutputFileStream ofstream(patchedCndFile);
28+
OutputFileStream ofstream(patchedCndFile, /*truncate=*/true);
2929

3030
/* Copy input cnd file to output stream until materials section */
3131
const auto matSectionOffset = CND::getOffset_Materials(ifstream);
@@ -78,7 +78,7 @@ using namespace libim::utils;
7878

7979
/* Open new output cnd file */
8080
const std::string patchedCndFile = cndFile + ".patched";
81-
OutputFileStream ofstream(patchedCndFile);
81+
OutputFileStream ofstream(patchedCndFile, /*truncate=*/true);
8282

8383
/* Copy input cnd file to output stream until materials section */
8484
const auto keySectionOffset = CND::getOffset_Keyframes(ifstream, cndHeader);

programs/gobext/main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ bool extractGob(std::shared_ptr<const GobFileDirectory> gobDir, std::string outD
120120
}
121121

122122
/* Open output file stream */
123-
OutputFileStream ofs(outPath);
123+
OutputFileStream ofs(outPath, /*truncate=*/true);
124124

125125
/* Write entry to file */
126126
ByteArray buffer(4096);

0 commit comments

Comments
 (0)