Fix 'O_CREAT' flag handling in 'open()'

Fixes #313.
This commit is contained in:
Christian Prochaska 2012-08-06 18:52:37 +02:00 committed by Norman Feske
parent 8c306bde67
commit 280fc59edf
7 changed files with 65 additions and 21 deletions

View File

@ -469,7 +469,7 @@ class Plugin : public Libc::Plugin
if ((flags & O_EXCL) == O_EXCL)
ffat_flags |= FA_CREATE_NEW;
else
ffat_flags |= FA_CREATE_ALWAYS;
ffat_flags |= FA_OPEN_ALWAYS;
}
FRESULT res = f_open(&ffat_file, pathname, ffat_flags);

View File

@ -499,16 +499,34 @@ class Plugin : public Libc::Plugin
* Open directory that contains the file to be opened/created
*/
File_system::Dir_handle const dir_handle =
file_system()->dir(dir_path, false);
file_system()->dir(dir_path, false);
Node_handle_guard guard(dir_handle);
File_system::File_handle handle;
/*
* Open or create file
*/
bool const create = (flags & O_CREAT) != 0;
File_system::File_handle const handle =
file_system()->file(dir_handle, basename, mode, create);
bool opened = false;
while (!opened) {
try {
handle = file_system()->file(dir_handle, basename, mode, create);
opened = true;
} catch (File_system::Node_already_exists) {
if (flags & O_EXCL)
throw File_system::Node_already_exists();
/* try to open the existing file */
try {
handle = file_system()->file(dir_handle, basename, mode, false);
opened = true;
} catch (File_system::Lookup_failed) {
/* the file got deleted in the meantime */
}
}
}
Plugin_context *context = new (Genode::env()->heap())
Plugin_context(handle);

View File

@ -277,7 +277,7 @@ namespace File_system {
throw Permission_denied();
if (create)
ffat_flags |= FA_CREATE_ALWAYS; /* overwrite existing file */
ffat_flags |= FA_CREATE_NEW;
if ((mode == READ_ONLY) || (mode == READ_WRITE))
ffat_flags |= FA_READ;

View File

@ -73,6 +73,10 @@ int main(int argc, char *argv[])
CALL_AND_CHECK(count, write(fd, pattern, pattern_size), (size_t)count == pattern_size, "");
CALL_AND_CHECK(ret, close(fd), ret == 0, "");
/* open the file with O_CREAT again (should have no effect on the file) */
CALL_AND_CHECK(fd, open(file_name, O_CREAT | O_WRONLY), fd >= 0, "file_name=%s", file_name);
CALL_AND_CHECK(ret, close(fd), ret == 0, "");
/* query file status of new file */
struct stat stat_buf;
CALL_AND_CHECK(ret, stat(file_name, &stat_buf), ret == 0, "file_name=%s", file_name);

View File

@ -67,7 +67,7 @@ namespace Noux {
OPEN_MODE_WRONLY = 1,
OPEN_MODE_RDWR = 2,
OPEN_MODE_ACCMODE = 3,
OPEN_MODE_CREATE = 0x0200,
OPEN_MODE_CREATE = 0x0800, /* libc O_EXCL */
};
enum {
@ -275,7 +275,8 @@ namespace Noux {
enum Stat_error { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS };
enum Fchdir_error { FCHDIR_ERR_NOT_DIR = NUM_GENERAL_ERRORS };
enum Fcntl_error { FCNTL_ERR_CMD_INVALID = NUM_GENERAL_ERRORS };
enum Open_error { OPEN_ERR_UNACCESSIBLE, OPEN_ERR_NO_PERM };
enum Open_error { OPEN_ERR_UNACCESSIBLE, OPEN_ERR_NO_PERM,
OPEN_ERR_EXISTS };
enum Execve_error { EXECVE_NONEXISTENT = NUM_GENERAL_ERRORS };
enum Unlink_error { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM };
enum Rename_error { RENAME_ERR_NO_ENTRY, RENAME_ERR_CROSS_FS,

View File

@ -607,19 +607,37 @@ namespace {
return 0;
}
if (flags & O_CREAT)
unlink(pathname);
Genode::strncpy(sysio()->open_in.path, pathname, sizeof(sysio()->open_in.path));
sysio()->open_in.mode = flags;
if (!noux()->syscall(Noux::Session::SYSCALL_OPEN)) {
/*
* XXX we should return meaningful errno values
*/
PDBG("ENOENT (sysio()->error.open=%d)", sysio()->error.open);
errno = ENOENT;
return 0;
bool opened = false;
while (!opened) {
Genode::strncpy(sysio()->open_in.path, pathname, sizeof(sysio()->open_in.path));
sysio()->open_in.mode = flags;
if (noux()->syscall(Noux::Session::SYSCALL_OPEN))
opened = true;
else
switch (sysio()->error.open) {
case Noux::Sysio::OPEN_ERR_UNACCESSIBLE:
if (!(flags & O_CREAT)) {
errno = ENOENT;
return 0;
}
/* O_CREAT is set, so try to create the file */
Genode::strncpy(sysio()->open_in.path, pathname, sizeof(sysio()->open_in.path));
sysio()->open_in.mode = flags | O_EXCL;
if (noux()->syscall(Noux::Session::SYSCALL_OPEN))
opened = true;
else
switch (sysio()->error.open) {
case Noux::Sysio::OPEN_ERR_EXISTS:
/* file has been created by someone else in the meantime */
break;
case Noux::Sysio::OPEN_ERR_NO_PERM: errno = EPERM; return 0;
default: errno = ENOENT; return 0;
}
break;
case Noux::Sysio::OPEN_ERR_NO_PERM: errno = EPERM; return 0;
case Noux::Sysio::OPEN_ERR_EXISTS: errno = EEXIST; return 0;
default: errno = ENOENT; return 0;
}
}
Libc::Plugin_context *context = noux_context(sysio()->open_out.fd);

View File

@ -416,7 +416,10 @@ namespace Noux {
error = Sysio::OPEN_ERR_NO_PERM; }
catch (::File_system::Invalid_handle) {
error = Sysio::OPEN_ERR_NO_PERM; }
catch (::File_system::Lookup_failed) { }
catch (::File_system::Lookup_failed) {
error = Sysio::OPEN_ERR_UNACCESSIBLE; }
catch (::File_system::Node_already_exists) {
error = Sysio::OPEN_ERR_EXISTS; }
sysio->error.open = error;
return 0;