in fs/yaffs2/yaffsfs.c [774:995]
int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
{
struct yaffs_obj *obj = NULL;
struct yaffs_obj *dir = NULL;
YCHAR *name;
int handle = -1;
struct yaffsfs_FileDes *fd = NULL;
int openDenied = 0;
int symDepth = 0;
int errorReported = 0;
int rwflags = oflag & (O_RDWR | O_RDONLY | O_WRONLY);
u8 shareRead = (sharing & YAFFS_SHARE_READ) ? 1 : 0;
u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0;
u8 sharedReadAllowed;
u8 sharedWriteAllowed;
u8 alreadyReading;
u8 alreadyWriting;
u8 readRequested;
u8 writeRequested;
int notDir = 0;
int loop = 0;
if (!path) {
yaffsfs_SetError(-EFAULT);
return -1;
}
if (yaffsfs_CheckPath(path) < 0) {
yaffsfs_SetError(-ENAMETOOLONG);
return -1;
}
/* O_EXCL only has meaning if O_CREAT is specified */
if (!(oflag & O_CREAT))
oflag &= ~(O_EXCL);
/* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
if ((oflag & O_CREAT) & (oflag & O_EXCL))
oflag &= ~(O_TRUNC);
/* Todo: Are there any more flag combos to sanitise ? */
/* Figure out if reading or writing is requested */
readRequested = (rwflags == O_RDWR || rwflags == O_RDONLY) ? 1 : 0;
writeRequested = (rwflags == O_RDWR || rwflags == O_WRONLY) ? 1 : 0;
yaffsfs_Lock();
handle = yaffsfs_NewHandleAndFileDes();
if (handle < 0) {
yaffsfs_SetError(-ENFILE);
errorReported = 1;
} else {
fd = yaffsfs_HandleToFileDes(handle);
/* try to find the exisiting object */
obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL);
obj = yaffsfs_FollowLink(obj, symDepth++, &loop);
if (obj &&
obj->variant_type != YAFFS_OBJECT_TYPE_FILE &&
obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
obj = NULL;
if (obj) {
/* The file already exists or it might be a directory */
/* A directory can't be opened as a file */
if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
openDenied = 1;
yaffsfs_SetError(-EISDIR);
errorReported = 1;
}
/* Open should fail if O_CREAT and O_EXCL are specified
* for a file that exists.
*/
if (!errorReported &&
(oflag & O_EXCL) && (oflag & O_CREAT)) {
openDenied = 1;
yaffsfs_SetError(-EEXIST);
errorReported = 1;
}
/* Check file permissions */
if (readRequested && !(obj->yst_mode & S_IREAD))
openDenied = 1;
if (writeRequested && !(obj->yst_mode & S_IWRITE))
openDenied = 1;
if (!errorReported && writeRequested &&
obj->my_dev->read_only) {
openDenied = 1;
yaffsfs_SetError(-EROFS);
errorReported = 1;
}
if (openDenied && !errorReported) {
yaffsfs_SetError(-EACCES);
errorReported = 1;
}
/* Check sharing of an existing object. */
if (!openDenied) {
struct yaffsfs_FileDes *fdx;
int i;
sharedReadAllowed = 1;
sharedWriteAllowed = 1;
alreadyReading = 0;
alreadyWriting = 0;
for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
fdx = &yaffsfs_fd[i];
if (fdx->handleCount > 0 &&
fdx->inodeId >= 0 &&
yaffsfs_inode[fdx->inodeId].iObj
== obj) {
if (!fdx->shareRead)
sharedReadAllowed = 0;
if (!fdx->shareWrite)
sharedWriteAllowed = 0;
if (fdx->reading)
alreadyReading = 1;
if (fdx->writing)
alreadyWriting = 1;
}
}
if ((!sharedReadAllowed && readRequested) ||
(!shareRead && alreadyReading) ||
(!sharedWriteAllowed && writeRequested) ||
(!shareWrite && alreadyWriting)) {
openDenied = 1;
yaffsfs_SetError(-EBUSY);
errorReported = 1;
}
}
}
/* If we could not open an existing object, then let's see if
* the directory exists. If not, error.
*/
if (!obj && !errorReported) {
dir = yaffsfs_FindDirectory(NULL, path, &name, 0,
¬Dir, &loop);
if (!dir && notDir) {
yaffsfs_SetError(-ENOTDIR);
errorReported = 1;
} else if (loop) {
yaffsfs_SetError(-ELOOP);
errorReported = 1;
} else if (!dir) {
yaffsfs_SetError(-ENOENT);
errorReported = 1;
}
}
if (!obj && dir && !errorReported && (oflag & O_CREAT)) {
/* Let's see if we can create this file */
if (dir->my_dev->read_only) {
yaffsfs_SetError(-EROFS);
errorReported = 1;
} else if (yaffsfs_TooManyObjects(dir->my_dev)) {
yaffsfs_SetError(-ENFILE);
errorReported = 1;
} else
obj = yaffs_create_file(dir, name, mode, 0, 0);
if (!obj && !errorReported) {
yaffsfs_SetError(-ENOSPC);
errorReported = 1;
}
}
if (!obj && dir && !errorReported && !(oflag & O_CREAT)) {
yaffsfs_SetError(-ENOENT);
errorReported = 1;
}
if (obj && !openDenied) {
int inodeId = yaffsfs_GetInodeIdForObject(obj);
if (inodeId < 0) {
/*
* Todo: Fix any problem if inodes run out,
* That can't happen if the number of inode
* items >= number of handles.
*/
}
fd->inodeId = inodeId;
fd->reading = readRequested;
fd->writing = writeRequested;
fd->append = (oflag & O_APPEND) ? 1 : 0;
fd->position = 0;
fd->shareRead = shareRead;
fd->shareWrite = shareWrite;
/* Hook inode to object */
obj->my_inode = (void *)&yaffsfs_inode[inodeId];
if ((oflag & O_TRUNC) && fd->writing)
yaffs_resize_file(obj, 0);
} else {
yaffsfs_PutHandle(handle);
if (!errorReported)
yaffsfs_SetError(0); /* Problem */
handle = -1;
}
}
yaffsfs_Unlock();
return handle;
}