IN PEXT2_VCB Vcb,
IN PEXT2_MCB Parent,
IN PEXT2_MCB Mcb,
- IN USHORT Linkdep
+ IN ULONG Linkdep
)
{
NTSTATUS Status = STATUS_LINK_FAILED;
/* exit if we jump into a possible symlink forever loop */
if ((Linkdep + 1) > EXT2_MAX_NESTED_LINKS ||
- IoGetRemainingStackSize() < 1024) {
+ IoGetRemainingStackSize() < 1024) {
_SEH2_LEAVE;
}
bOemBuffer = TRUE;
RtlZeroMemory(OemName.Buffer, OemName.MaximumLength);
- Status = Ext2ReadInode(
+ Status = Ext2ReadSymlink(
IrpContext,
Vcb,
Mcb,
- (ULONGLONG)0,
OemName.Buffer,
(ULONG)(Mcb->Inode.i_size),
- FALSE,
NULL);
if (!NT_SUCCESS(Status)) {
_SEH2_LEAVE;
}
if (Target == NULL /* link target doesn't exist */ ||
- Target == Mcb /* symlink points to itself */ ||
- IsMcbSpecialFile(Target) /* target not resolved*/ ||
- IsFileDeleted(Target) /* target deleted */ ) {
+ Target == Mcb /* symlink points to itself */ ||
+ IsMcbSpecialFile(Target) /* target not resolved*/ ||
+ IsFileDeleted(Target) /* target deleted */ ) {
if (Target) {
ASSERT(Target->Refercount > 0);
}
ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
- Mcb->FileAttr = FILE_ATTRIBUTE_NORMAL;
Mcb->Target = NULL;
} else if (IsMcbSymLink(Target)) {
SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
ASSERT(Mcb->Target->Refercount > 0);
- Mcb->FileAttr = Target->FileAttr;
-
+
} else {
Mcb->Target = Target;
SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
ASSERT(Mcb->Target->Refercount > 0);
- Mcb->FileAttr = Target->FileAttr;
+ }
+
+ /* add directory flag to file attribute */
+ if (Mcb->Target && IsMcbDirectory(Mcb->Target)) {
+ Mcb->FileAttr |= FILE_ATTRIBUTE_DIRECTORY;
}
} _SEH2_FINALLY {
IN PUNICODE_STRING FullName,
IN PEXT2_MCB Parent,
OUT PEXT2_MCB * Ext2Mcb,
- IN USHORT Linkdep
+ IN ULONG Linkdep
)
{
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
BOOLEAN bParent = FALSE;
BOOLEAN bDirectory = FALSE;
BOOLEAN LockAcquired = FALSE;
+ BOOLEAN bNotFollow = FALSE;
_SEH2_TRY {
ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
LockAcquired = TRUE;
+ bNotFollow = IsFlagOn(Linkdep, EXT2_LOOKUP_NOT_FOLLOW);
+#ifndef __REACTOS__
+ Linkdep = ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
+#else
+ ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
+#endif
+
*Ext2Mcb = NULL;
DEBUG(DL_RES, ("Ext2LookupFile: %wZ\n", FullName));
Parent = Mcb;
if (IsMcbSymLink(Mcb) && IsFileDeleted(Mcb->Target) &&
- (Mcb->Refercount == 1)) {
+ Mcb->Refercount == 1) {
ASSERT(Mcb->Target);
ASSERT(Mcb->Target->Refercount > 0);
}
/* set inode attribute */
- if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(Mcb->Inode.i_mode)) {
+ if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_READONLY);
}
if (S_ISDIR(Mcb->Inode.i_mode)) {
SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY);
} else {
- SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
- if (!S_ISREG(Mcb->Inode.i_mode) &&
- !S_ISLNK(Mcb->Inode.i_mode)) {
+ if (S_ISREG(Mcb->Inode.i_mode)) {
+ SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
+ } else if (S_ISLNK(Mcb->Inode.i_mode)) {
+ SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+ } else {
SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
}
}
Mcb->ChangeTime = Ext2NtTime(Mcb->Inode.i_mtime);
/* process symlink */
- if (S_ISLNK(Mcb->Inode.i_mode)) {
+ if (S_ISLNK(Mcb->Inode.i_mode) && !bNotFollow) {
Ext2FollowLink( IrpContext,
Vcb,
Parent,
Ext2DerefMcb(Parent);
if (bh)
- brelse(bh);
+ __brelse(bh);
if (!NT_SUCCESS(Status)) {
if (de)
errorout:
if (bh)
- brelse (bh);
+ __brelse (bh);
return Ext2WinntError(rc);
}
BOOLEAN DeleteOnClose;
BOOLEAN TemporaryFile;
BOOLEAN CaseSensitive;
+ BOOLEAN OpenReparsePoint;
ACCESS_MASK DesiredAccess;
ULONG ShareAccess;
+ ULONG CcbFlags = 0;
RtlZeroMemory(&FileName, sizeof(UNICODE_STRING));
NoEaKnowledge = IsFlagOn(Options, FILE_NO_EA_KNOWLEDGE);
DeleteOnClose = IsFlagOn(Options, FILE_DELETE_ON_CLOSE);
+ /* Try to open reparse point (symlink) itself ? */
+ OpenReparsePoint = IsFlagOn(Options, FILE_OPEN_REPARSE_POINT);
+
CaseSensitive = IsFlagOn(IrpSp->Flags, SL_CASE_SENSITIVE);
TemporaryFile = IsFlagOn(IrpSp->Parameters.Create.FileAttributes,
&FileName,
ParentMcb,
&Mcb,
- 0 );
+ 0 /* always follow link */
+ );
McbExisting:
if (!NT_SUCCESS(Status)) {
_SEH2_LEAVE;
}
- if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(ParentFcb->Mcb->Inode.i_mode)) {
+ if (!Ext2CheckFileAccess(Vcb, ParentMcb, Ext2FileCanWrite)) {
Status = STATUS_ACCESS_DENIED;
_SEH2_LEAVE;
}
if (IsMcbDirectory(Mcb)) {
if ((CreateDisposition != FILE_OPEN) &&
- (CreateDisposition != FILE_OPEN_IF)) {
+ (CreateDisposition != FILE_OPEN_IF)) {
Status = STATUS_OBJECT_NAME_COLLISION;
Ext2DerefMcb(Mcb);
/* refer it's target if it's a symlink, so both refered */
if (IsMcbSymLink(Mcb)) {
- if (IsFileDeleted(Mcb->Target)) {
+
+ if (OpenReparsePoint) {
+ /* set Ccb flag */
+ CcbFlags = CCB_OPEN_REPARSE_POINT;
+ } else if (IsFileDeleted(Mcb->Target)) {
DbgBreak();
SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
}
// Check readonly flag
- if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(Mcb->Inode.i_mode)) {
+ if (BooleanFlagOn(DesiredAccess, FILE_GENERIC_READ) &&
+ !Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanRead)) {
+ Status = STATUS_ACCESS_DENIED;
+ _SEH2_LEAVE;
+ }
+ if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
if (BooleanFlagOn(DesiredAccess, FILE_WRITE_DATA | FILE_APPEND_DATA |
FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD)) {
Status = STATUS_ACCESS_DENIED;
&(Fcb->ShareAccess) );
}
- Ccb = Ext2AllocateCcb(SymLink);
+ Ccb = Ext2AllocateCcb(CcbFlags, SymLink);
if (!Ccb) {
Status = STATUS_INSUFFICIENT_RESOURCES;
DbgBreak();
return STATUS_SHARING_VIOLATION;
}
- Ccb = Ext2AllocateCcb(NULL);
+ Ccb = Ext2AllocateCcb(0, NULL);
if (Ccb == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
Inode.i_sb = &Vcb->sb;
Inode.i_ino = iNo;
Inode.i_ctime = Inode.i_mtime =
- Inode.i_atime = Ext2LinuxTime(SysTime);
- Inode.i_uid = Parent->Inode->i_uid;
- Inode.i_gid = Parent->Inode->i_gid;
+ Inode.i_atime = Ext2LinuxTime(SysTime);
+ Inode.i_uid = Vcb->uid;
+ Inode.i_gid = Vcb->gid;
Inode.i_generation = Parent->Inode->i_generation;
Inode.i_mode = S_IPERMISSION_MASK &
Parent->Inode->i_mode;
/* Force using extent */
if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
Inode.i_flags |= EXT2_EXTENTS_FL;
+ ext4_ext_tree_init(IrpContext, NULL, &Inode);
+ /* ext4_ext_tree_init will save inode body */
+ } else {
+ /* save inode body to cache */
+ Ext2SaveInode(IrpContext, Vcb, &Inode);
}
/* add new entry to its parent */