FILE * eC_stderr(void);
-unsigned int System_MoveFile(const char * source, const char * dest);
+unsigned int System_MoveFile(const char * source, const char * dest, unsigned int replaceAndFlush);
unsigned int System_RenameFile(const char * oldName, const char * newName);
unsigned int __ecereNameSpace__ecere__sys__MoveFile(const char * source, const char * dest)
{
-return System_MoveFile(source, dest);
+return System_MoveFile(source, dest, 0);
+}
+
+unsigned int __ecereNameSpace__ecere__sys__MoveFileEx(const char * source, const char * dest, unsigned int options)
+{
+return System_MoveFile(source, dest, (unsigned int)options);
}
unsigned int __ecereNameSpace__ecere__sys__RenameFile(const char * oldName, const char * newName)
static struct __ecereNameSpace__ecere__com__Class * __ecereClass___ecereNameSpace__ecere__sys__GuiErrorCode;
+static struct __ecereNameSpace__ecere__com__Class * __ecereClass___ecereNameSpace__ecere__sys__MoveFileOptions;
+
static struct __ecereNameSpace__ecere__com__Class * __ecereClass___ecereNameSpace__ecere__sys__System;
extern struct __ecereNameSpace__ecere__com__Class * __ecereClass___ecereNameSpace__ecere__com__Array_TPL_String_;
__ecereNameSpace__ecere__com__eEnum_AddFixedValue(class, "graphicsLoadingFailed", 259);
__ecereNameSpace__ecere__com__eEnum_AddFixedValue(class, "modeSwitchFailed", 260);
__ecereNameSpace__ecere__com__eSystem_RegisterFunction("ecere::sys::MoveFile", "bool ecere::sys::MoveFile(const char * source, const char * dest)", __ecereNameSpace__ecere__sys__MoveFile, module, 1);
+class = __ecereNameSpace__ecere__com__eSystem_RegisterClass(2, "ecere::sys::MoveFileOptions", "uint", 0, 0, (void *)0, (void *)0, module, 1, 1);
+if(((struct __ecereNameSpace__ecere__com__Module *)(((char *)module + sizeof(struct __ecereNameSpace__ecere__com__Instance))))->application == ((struct __ecereNameSpace__ecere__com__Module *)(((char *)__thisModule + sizeof(struct __ecereNameSpace__ecere__com__Instance))))->application && class)
+__ecereClass___ecereNameSpace__ecere__sys__MoveFileOptions = class;
+__ecereNameSpace__ecere__com__eClass_AddBitMember(class, "overwrite", "bool", 1, 0, 1);
+__ecereNameSpace__ecere__com__eClass_AddBitMember(class, "sync", "bool", 1, 1, 1);
+__ecereNameSpace__ecere__com__eSystem_RegisterFunction("ecere::sys::MoveFileEx", "bool ecere::sys::MoveFileEx(const char * source, const char * dest, ecere::sys::MoveFileOptions options)", __ecereNameSpace__ecere__sys__MoveFileEx, module, 1);
__ecereNameSpace__ecere__com__eSystem_RegisterFunction("ecere::sys::RenameFile", "bool ecere::sys::RenameFile(const char * oldName, const char * newName)", __ecereNameSpace__ecere__sys__RenameFile, module, 1);
__ecereNameSpace__ecere__com__eSystem_RegisterFunction("ecere::sys::DeleteFile", "bool ecere::sys::DeleteFile(const char * fileName)", __ecereNameSpace__ecere__sys__DeleteFile, module, 1);
__ecereNameSpace__ecere__com__eSystem_RegisterFunction("ecere::sys::MakeDir", "bool ecere::sys::MakeDir(const char * path)", __ecereNameSpace__ecere__sys__MakeDir, module, 1);
FileAttribs FILE_FileExists(const char * fileName);
-bool System_MoveFile(const char * source, const char * dest)
+bool System_MoveFile(const char * source, const char * dest, uint replaceAndFlush)
{
#ifdef __WIN32__
bool result;
uint16 * _wsource = __ecereNameSpace__ecere__sys__UTF8toUTF16(source, null);
uint16 * _wdest = __ecereNameSpace__ecere__sys__UTF8toUTF16(dest, null);
- result = MoveFileEx(_wsource, _wdest, MOVEFILE_COPY_ALLOWED) != 0;
+ // TODO: Select options individually
+ result = MoveFileEx(_wsource, _wdest, MOVEFILE_COPY_ALLOWED | (replaceAndFlush ? MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH : 0)) != 0;
__ecereNameSpace__ecere__com__eSystem_Delete(_wsource);
__ecereNameSpace__ecere__com__eSystem_Delete(_wdest);
return result;
FILE *eC_stderr(void);
// IMPLEMENTED IN _System.c
-bool System_MoveFile(const char * source, const char * dest);
+bool System_MoveFile(const char * source, const char * dest, uint replaceAndFlush);
bool System_RenameFile(const char * oldName, const char * newName);
bool System_DeleteFile(const char * fileName);
bool System_MakeDir(const char * path);
// --- File, directory & environment manipulation ---
#undef MoveFile
+#undef MoveFileEx
public bool MoveFile(const char * source, const char * dest)
{
- return System_MoveFile(source, dest);
+ return System_MoveFile(source, dest, 0);
+}
+
+public class MoveFileOptions : uint32 { public: bool overwrite:1; bool sync:1; };
+
+public bool MoveFileEx(const char * source, const char * dest, MoveFileOptions options)
+{
+ return System_MoveFile(source, dest, options);
}
public bool RenameFile(const char * oldName, const char * newName)
static SettingsIOResult writeConfigFile(const char * path, Class dataType, void * data)
{
SettingsIOResult result = error;
- SafeFile sf;
- sf = safeWriteFileOpen(path, write);
- if(sf.file)
+ SafeFile sf = SafeFile::open(path, write);
+ if(sf)
{
WriteECONObject(sf.file, dataType, data, 0);
+ sf.sync();
delete sf;
result = success;
}
SafeFile sf;
if(!FileExists(path))
result = fileNotFound;
- else if((sf = safeWriteFileOpen(path, read)))
+ else if((sf = SafeFile::open(path, read)))
{
JSONResult jsonResult;
{
char path[MAX_LOCATION];
char tmp[MAX_LOCATION];
- ~SafeFile()
+ SafeFile ::open(const char * path, FileOpenMode mode)
{
- delete file;
- // how to make this atomic ?
- if(mode == write)
+ SafeFile result = null;
+ if(mode == write || mode == read)
{
+ SafeFile sf { mode = mode };
int c;
- for(c = 0; c < 10; c++)
+ bool locked = false;
+ FileLock lockType = mode == write ? exclusive : shared;
+
+ strcpy(sf.path, path);
+ strcpy(sf.tmp, path);
+ strcat(sf.tmp, ".tmp");
+ if(mode == write && FileExists(sf.tmp).isFile)
+ DeleteFile(sf.tmp);
+
+ sf.file = FileOpen(mode == write ? sf.tmp : path, mode);
+ if(sf.file)
{
- if(FileExists(path).isFile)
- DeleteFile(path);
+ for(c = 0; c < 10 && !(locked = sf.file.Lock(lockType, 0, 0, false)); c++) Sleep(0.01);
+ if(locked)
+ result = sf;
+ else if(mode == write)
+ PrintLn($"warning: SafeFile::open: unable to obtain exclusive lock on temporary file for writing: ", sf.tmp);
else
- {
- MoveFile(tmp, path);
- if(FileExists(path).isFile)
- break;
- }
+ PrintLn($"warning: SafeFile::open: unable to obtain shared lock on file for reading: ", path);
}
+ else if(mode == write)
+ PrintLn($"warning: SafeFile::open: unable to open temporary file for writing: ", sf.tmp);
+ else
+ PrintLn($"warning: SafeFile::open: unable to open file for reading: ", path);
+
+ if(!result)
+ delete sf;
}
+ else
+ PrintLn($"warning: SafeFile::open: does not yet support FileOpenMode::", mode);
+ return result;
}
-}
-SafeFile safeWriteFileOpen(const char * path, FileOpenMode mode)
-{
- SafeFile sf { mode = mode };
- int c;
- bool locked = false;
- strcpy(sf.path, path);
- strcpy(sf.tmp, path);
- strcat(sf.tmp, ".tmp");
- if(mode == write)
- {
- if(FileExists(sf.tmp).isFile)
- DeleteFile(sf.tmp);
- sf.file = FileOpen(sf.tmp, write);
- if(sf.file)
+ void sync()
+ {
+ if(file && mode == write)
{
- for(c = 0; c < 10 && !(locked = sf.file.Lock(exclusive, 0, 0, false)); c++);
- if(!locked)
+ int c;
+ File f = FileOpen(path, FileExists(path) ? read : write);
+ if(f)
{
- delete sf.file;
- PrintLn($"warning: safeWriteFileOpen: unable to obtain exclusive lock on temporary file for writing: ", sf.tmp);
+ bool locked = true;
+ for(c = 0; c < 10 && !(locked = f.Lock(exclusive, 0,0, false)); c++) Sleep(0.01);
+
+ if(locked)
+ {
+ f.Unlock(0,0, false);
+ delete f;
+ file.Unlock(0,0, false);
+ delete file;
+
+ for(c = 0; c < 10; c++)
+ {
+ if(MoveFileEx(tmp, path, { true, true }))
+ break;
+ else
+ Sleep(0.01);
+ }
+ }
+ else
+ {
+ delete f;
+ PrintLn($"warning: SafeFile::sync: failed to lock file", mode);
+ }
}
}
- else
- PrintLn($"warning: safeWriteFileOpen: unable to open temporary file for writing: ", sf.tmp);
}
- else if(mode == read)
+
+
+ ~SafeFile()
{
- sf.file = FileOpen(path, read);
- if(sf.file)
+ if(file)
{
- for(c = 0; c < 10 && !(locked = sf.file.Lock(shared, 0, 0, false)); c++) Sleep(0.01);
- if(!locked)
- {
- delete sf.file;
- PrintLn($"warning: safeWriteFileOpen: unable to obtain shared lock on file for reading: ", path);
- }
+ file.Unlock(0,0, false);
+ delete file;
}
}
- else
- PrintLn($"warning: safeWriteFileOpen: does not yet support FileOpenMode::", mode);
- return sf;
}
class RecentFilesData