static status_t ext2_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie) { Volume* volume = (Volume*)_volume->private_volume; Inode* inode = (Inode*)_node->private_node; // opening a directory read-only is allowed, although you can't read // any data from it. if (inode->IsDirectory() && (openMode & O_RWMASK) != 0) return B_IS_A_DIRECTORY; status_t status = inode->CheckPermissions(open_mode_to_access(openMode) | (openMode & O_TRUNC ? W_OK : 0)); if (status != B_OK) return status; // Prepare the cookie file_cookie* cookie = new(std::nothrow) file_cookie; if (cookie == NULL) return B_NO_MEMORY; ObjectDeleter<file_cookie> cookieDeleter(cookie); cookie->open_mode = openMode & EXT2_OPEN_MODE_USER_MASK; cookie->last_size = inode->Size(); cookie->last_notification = system_time(); MethodDeleter<Inode, status_t> fileCacheEnabler(&Inode::EnableFileCache); if ((openMode & O_NOCACHE) != 0) { status = inode->DisableFileCache(); if (status != B_OK) return status; fileCacheEnabler.SetTo(inode); } // Should we truncate the file? if ((openMode & O_TRUNC) != 0) { if ((openMode & O_RWMASK) == O_RDONLY) return B_NOT_ALLOWED; Transaction transaction(volume->GetJournal()); inode->WriteLockInTransaction(transaction); status_t status = inode->Resize(transaction, 0); if (status == B_OK) status = inode->WriteBack(transaction); if (status == B_OK) status = transaction.Done(); if (status != B_OK) return status; // TODO: No need to notify file size changed? } fileCacheEnabler.Detach(); cookieDeleter.Detach(); *_cookie = cookie; return B_OK; }
static status_t btrfs_open(fs_volume* /*_volume*/, fs_vnode* _node, int openMode, void** _cookie) { Inode* inode = (Inode*)_node->private_node; // opening a directory read-only is allowed, although you can't read // any data from it. if (inode->IsDirectory() && (openMode & O_RWMASK) != 0) return B_IS_A_DIRECTORY; status_t status = inode->CheckPermissions(open_mode_to_access(openMode) | (openMode & O_TRUNC ? W_OK : 0)); if (status != B_OK) return status; // Prepare the cookie file_cookie* cookie = new(std::nothrow) file_cookie; if (cookie == NULL) return B_NO_MEMORY; ObjectDeleter<file_cookie> cookieDeleter(cookie); cookie->open_mode = openMode & BTRFS_OPEN_MODE_USER_MASK; cookie->last_size = inode->Size(); cookie->last_notification = system_time(); if ((openMode & O_NOCACHE) != 0 && inode->FileCache() != NULL) { // Disable the file cache, if requested? status = file_cache_disable(inode->FileCache()); if (status != B_OK) return status; } cookieDeleter.Detach(); *_cookie = cookie; return B_OK; }
/*static*/ status_t Inode::Create(Transaction& transaction, Inode* parent, const char* name, int32 mode, int openMode, uint8 type, bool* _created, ino_t* _id, Inode** _inode, fs_vnode_ops* vnodeOps, uint32 publishFlags) { TRACE("Inode::Create()\n"); Volume* volume = transaction.GetVolume(); DirectoryIterator* entries = NULL; ObjectDeleter<DirectoryIterator> entriesDeleter; if (parent != NULL) { parent->WriteLockInTransaction(transaction); TRACE("Inode::Create(): Looking up entry destination\n"); HTree htree(volume, parent); status_t status = htree.Lookup(name, &entries); if (status == B_ENTRY_NOT_FOUND) { panic("We need to add the first node.\n"); return B_ERROR; } if (status != B_OK) return status; entriesDeleter.SetTo(entries); TRACE("Inode::Create(): Looking up to see if file already exists\n"); ino_t entryID; status = entries->FindEntry(name, &entryID); if (status == B_OK) { // File already exists TRACE("Inode::Create(): File already exists\n"); if (S_ISDIR(mode) || S_ISLNK(mode) || (openMode & O_EXCL) != 0) return B_FILE_EXISTS; Vnode vnode(volume, entryID); Inode* inode; status = vnode.Get(&inode); if (status != B_OK) { TRACE("Inode::Create() Failed to get the inode from the " "vnode\n"); return B_ENTRY_NOT_FOUND; } if (inode->IsDirectory() && (openMode & O_RWMASK) != O_RDONLY) return B_IS_A_DIRECTORY; if ((openMode & O_DIRECTORY) != 0 && !inode->IsDirectory()) return B_NOT_A_DIRECTORY; if (inode->CheckPermissions(open_mode_to_access(openMode) | ((openMode & O_TRUNC) != 0 ? W_OK : 0)) != B_OK) return B_NOT_ALLOWED; if ((openMode & O_TRUNC) != 0) { // Truncate requested TRACE("Inode::Create(): Truncating file\n"); inode->WriteLockInTransaction(transaction); status = inode->Resize(transaction, 0); if (status != B_OK) return status; } if (_created != NULL) *_created = false; if (_id != NULL) *_id = inode->ID(); if (_inode != NULL) *_inode = inode; if (_id != NULL || _inode != NULL) vnode.Keep(); TRACE("Inode::Create(): Done opening file\n"); return B_OK; /*} else if ((mode & S_ATTR_DIR) == 0) { TRACE("Inode::Create(): (mode & S_ATTR_DIR) == 0\n"); return B_BAD_VALUE;*/ } else if ((openMode & O_DIRECTORY) != 0) { TRACE("Inode::Create(): (openMode & O_DIRECTORY) != 0\n"); return B_ENTRY_NOT_FOUND; } // Return to initial position TRACE("Inode::Create(): Restarting iterator\n"); entries->Restart(); } status_t status; if (parent != NULL) { status = parent->CheckPermissions(W_OK); if (status != B_OK) return status; } TRACE("Inode::Create(): Allocating inode\n"); ino_t id; status = volume->AllocateInode(transaction, parent, mode, id); if (status != B_OK) { ERROR("Inode::Create(): AllocateInode() failed\n"); return status; } if (entries != NULL) { size_t nameLength = strlen(name); status = entries->AddEntry(transaction, name, nameLength, id, type); if (status != B_OK) { ERROR("Inode::Create(): AddEntry() failed\n"); return status; } } TRACE("Inode::Create(): Creating inode\n"); Inode* inode = new(std::nothrow) Inode(volume); if (inode == NULL) return B_NO_MEMORY; TRACE("Inode::Create(): Getting node structure\n"); ext2_inode& node = inode->Node(); TRACE("Inode::Create(): Initializing inode data\n"); memset(&node, 0, sizeof(ext2_inode)); node.SetMode(mode); node.SetUserID(geteuid()); node.SetGroupID(parent != NULL ? parent->Node().GroupID() : getegid()); node.SetNumLinks(inode->IsDirectory() ? 2 : 1); TRACE("Inode::Create(): Updating time\n"); struct timespec timespec; _BigtimeToTimespec(real_time_clock_usecs(), ×pec); inode->SetAccessTime(×pec); inode->SetCreationTime(×pec); inode->SetModificationTime(×pec); node.SetFlags(parent->Flags() & EXT2_INODE_INHERITED); if (volume->HasExtentsFeature() && (inode->IsDirectory() || inode->IsFile())) { node.SetFlag(EXT2_INODE_EXTENTS); ExtentStream stream(volume, &node.extent_stream, 0); stream.Init(); ASSERT(stream.Check()); } if (sizeof(ext2_inode) < volume->InodeSize()) node.SetExtraInodeSize(sizeof(ext2_inode) - EXT2_INODE_NORMAL_SIZE); TRACE("Inode::Create(): Updating ID\n"); inode->fID = id; if (inode->IsDirectory()) { TRACE("Inode::Create(): Initializing directory\n"); status = inode->InitDirectory(transaction, parent); if (status != B_OK) { ERROR("Inode::Create(): InitDirectory() failed\n"); delete inode; return status; } } // TODO: Maybe it can be better /*if (volume->HasExtendedAttributes()) { TRACE("Inode::Create(): Initializing extended attributes\n"); uint32 blockGroup = 0; uint32 pos = 0; uint32 allocated; status = volume->AllocateBlocks(transaction, 1, 1, blockGroup, pos, allocated); if (status != B_OK) return status; // Clear the new block uint32 blockNum = volume->FirstDataBlock() + pos + volume->BlocksPerGroup() * blockGroup; CachedBlock cached(volume); cached.SetToWritable(transaction, blockNum, true); node.SetExtendedAttributesBlock(blockNum); }*/ TRACE("Inode::Create(): Saving inode\n"); status = inode->WriteBack(transaction); if (status != B_OK) { delete inode; return status; } TRACE("Inode::Create(): Creating vnode\n"); Vnode vnode; status = vnode.Publish(transaction, inode, vnodeOps, publishFlags); if (status != B_OK) return status; if (!inode->IsSymLink()) { // Vnode::Publish doesn't publish symlinks if (!inode->IsDirectory()) { status = inode->EnableFileCache(); if (status != B_OK) return status; } inode->WriteLockInTransaction(transaction); } if (_created) *_created = true; if (_id != NULL) *_id = id; if (_inode != NULL) *_inode = inode; if (_id != NULL || _inode != NULL) vnode.Keep(); TRACE("Inode::Create(): Deleting entries iterator\n"); DirectoryIterator* iterator = entriesDeleter.Detach(); TRACE("Inode::Create(): Entries iterator: %p\n", entries); delete iterator; TRACE("Inode::Create(): Done\n"); return B_OK; }
status_t Attribute::CheckAccess(const char* name, int openMode) { return fInode->CheckPermissions(open_mode_to_access(openMode) | (openMode & O_TRUNC ? W_OK : 0)); }