Commit 343b54e4 authored by Colin Granville's avatar Colin Granville Committed by ROOL

Fixed deletion of directory trees

Detail:
  Rewrite of directory enumeration so that when directory trees are deleted when they are completely deleted.
  Modified fsentry_func in CoreFN.c so that the ReadDirectory reason codes call the new Func_ReadDir1 which uses SMBFind_EnumDir implemented in SMB.c and SMBfind.h
Admin:
  Tested with Windows and Samba on Armbian.

Version 2.64. Tagged as 'OmniLanManFS-2_64'
parent 3c1bc966
/* (2.63)
/* (2.64)
*
* This file is automatically maintained by srccommit, do not edit manually.
*
*/
#define Module_MajorVersion_CMHG 2.63
#define Module_MajorVersion_CMHG 2.64
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 27 Apr 2020
#define Module_Date_CMHG 16 May 2020
#define Module_MajorVersion "2.63"
#define Module_Version 263
#define Module_MajorVersion "2.64"
#define Module_Version 264
#define Module_MinorVersion ""
#define Module_Date "27 Apr 2020"
#define Module_Date "16 May 2020"
#define Module_ApplicationDate "27-Apr-20"
#define Module_ApplicationDate "16-May-20"
#define Module_ComponentName "OmniLanManFS"
#define Module_FullVersion "2.63"
#define Module_HelpVersion "2.63 (27 Apr 2020)"
#define Module_LibraryVersionInfo "2:63"
#define Module_FullVersion "2.64"
#define Module_HelpVersion "2.64 (16 May 2020)"
#define Module_LibraryVersionInfo "2:64"
......@@ -37,6 +37,7 @@
#include "Omni.h"
#include "Transact.h"
#include "NameCache.h"
#include "SMBFind.h"
#define NAMEBUF_LEN (2*DOS_NAME_LEN)
......@@ -180,6 +181,54 @@ static err_t Dir_CallbackFn ( BYTE *entry, int format, bool *taken, void *pw )
/* ----------------- */
#ifdef LONGNAMES
static err_t Func_ReadDir1 ( int reason, char *path_name, char *buffer,
int n_names, int dir_offset, int buflen, int *pOutNread,
int *pOutNextOffset )
{
static SMBFind_t smbfind;
err_t res;
RD_Reason = reason;
RD_BufPtr = buffer;
RD_BufLen = buflen;
RD_CurCount = 0;
RD_ReqCount = n_names;
res = OK;
while ( dir_offset != -1 &&
res == OK && /* More names available */
RD_ReqCount > 0 ) /* More names wanted */
{
res = SMBFind_EnumDir(&smbfind, dir_offset, path_name, RD_ReqCount, Dir_CallbackFn, NULL, &dir_offset);
}
/* Process results */
if (res == EOUTOFMEM && RD_BufLen == -1 && RD_CurCount > 0)
{
/* Special result when client buffer space exhausted */
res = OK;
}
if ( res != OK )
{
/* Ran out of files, or error */
*pOutNextOffset = -1;
}
else
*pOutNextOffset = dir_offset;
*pOutNread = RD_CurCount;
if ( res == ENOMOREFILES )
return OK;
return res;
}
#endif
/* ----------------- */
/* Called in 2 situations
* - starting a search from scratch (dir_offset = 0)
* - continuing a search (dir_offset != 0)
......@@ -405,8 +454,13 @@ _kernel_oserror *fsentry_func ( int *R )
case FSEntry_Func_Reason_ReadDirectoryEntries:
case FSEntry_Func_Reason_ReadDirectoriesAndInformation:
case FSEntry_Func_Reason_ReadDirectoryEntriesAndInformation:
#ifdef LONGNAMES
err = Func_ReadDir1 ( R[0], name_R(1), name_R(2),
R[3], R[4], R[5], &R[3], &R[4] );
#else
err = Func_ReadDir ( R[0], name_R(1), name_R(2),
R[3], R[4], R[5], &R[3], &R[4] );
#endif
break;
default:
......
......@@ -95,6 +95,7 @@
#include "Attr.h" /* For InvalidateDrive */
#include "Xlate.h" /* For string functions */
#include "Auth.h"
#include "SMBFind.h"
/* Definitions ===================================================== */
......@@ -3269,3 +3270,170 @@ void SMB_AntiIdle ( void )
}
}
}
#define SMBFind_GetOffsetHi(offset) (((DWORD)(offset)) >> 16)
#define SMBFind_GetOffsetLow(offset) ((offset) & 0xffff)
#define SMBFind_SetOffset(offset) (((offset) << 16) | ((offset) & 0xffff))
static err_t SMBFind_Close(SMBFind_t *fnd)
{
if (fnd == NULL) return OK;
if (fnd->hS != NULL && fnd->SID != 0)
{
SMB_AbandonFind2( fnd->hS, fnd->SID);
fnd->hS = NULL;
fnd->SID = 0;
}
return OK;
}
err_t SMBFind_EnumDir(SMBFind_t *fnd, int dir_offset, const char *ro_path, int count,
ENUM_DIR_FN dirfn, void *dirfn_handle,
int *dir_offset_out)
{
static char DOSnamebuf[512];
err_t err = OK;
BYTE *p;
int SearchCount = 0;
int EndOfSearch;
int length, i;
struct TransactParms tp;
if (dir_offset < 0)
{
*dir_offset_out = -1;
return OK;
}
/*
* Wipe and FilerAct reduce dir_offset by 1 for every file deleted during
* enumeration.
*
* dir_offset is set to the offset into the directory of the next entry in the
* low 2 bytes (low_offset) and a copy of this in the high 2 bytes (hi_offset).
*
* The directory enumeration can continue with the existing FIND_FIRST SID if:
* 1) hi_offset is the same as the stored offset - ResumeKey is valid.
* 2) hi_offset = low_offset - if they are different deletions have occurred.
* 3) directory paths are the same.
*
* Otherwise the find is restarted and files are skipped until the offset
* is low_offset.
*/
if (dir_offset == 0 ||
(dir_offset != 0 &&
(SMBFind_GetOffsetHi(dir_offset) != fnd->Offset ||
SMBFind_GetOffsetHi(dir_offset) != SMBFind_GetOffsetLow(dir_offset) ||
strcmp(fnd->ROPath, ro_path) != 0)))
{
SMBFind_Close(fnd);
err = Xlt_ConvertPath( (char*)ro_path, DOSnamebuf );
if ( err != OK ) return err;
if ( DOSnamebuf[strlen( DOSnamebuf ) - 1] != '\\' )
strcat( DOSnamebuf, "\\");
strcat( DOSnamebuf, "*" );
hSHARE hS = GetShare(DOSnamebuf, &err);
if (err) return err;
fnd->hS = hS;
strcpy(fnd->ROPath, ro_path);
count += 2; /* include . and .. */
/* Initial search - note we accept SIX return parameters - contrary to
* Microsoft's own document - because it doesn't work if you only pass 5. Grr.
*/
Transact_init(&tp, 6 * 2); /* sizeof response Trans2_Parameters - 6 WORDs */
Transact_addsetupword(&tp, TRANSACT2_FINDFIRST);
/* Trans2_Parameters */
if (LM_Vars.namemode & NM_INTERNAL)
{
Transact_addword(&tp, ATTR_DIR | ATTR_SYS | ATTR_HID); /* SearchAttributes */
}
else
{
Transact_addword(&tp, ATTR_DIR); /* SearchAttributes */
}
Transact_addword(&tp, count); /* SearchCount */
Transact_addword(&tp, ffirst_RETURN_KEYS);/* Flags */
Transact_addword(&tp, 1); /* InformationLevel */
Transact_addlong(&tp, 0L); /* SearchStorageType -MBZ */
Transact_addstring(&tp, DOSnamebuf + 2); /* FileName[] */
err = SMB_Transact2(hS, &tp);
if (err != OK) return err;
p = tp.parms_out_buf;
fnd->SID = Transact_getword(p); p += 2;
fnd->Resume = dir_offset != 0 ? fnd->Resume = SMBFind_GetOffsetLow(dir_offset) : 0;
fnd->Offset = 0;
}
else
{
/* Continuation */
Transact_init(&tp, 4 * 2); /* sizeof response Trans2_Parameters 4 Words */
Transact_addsetupword(&tp, TRANSACT2_FINDNEXT);
Transact_addword(&tp, fnd->SID); /* SID */
Transact_addword(&tp, count); /* SearchCount */
Transact_addword(&tp, 1); /* InformationLevel */
Transact_addlong(&tp, fnd->ResumeKey); /* ResumeKey*/
Transact_addword(&tp, ffirst_RETURN_KEYS);/* Flags */
Transact_addstring(&tp, fnd->FileName);
err = SMB_Transact2(fnd->hS, &tp);
if (err != OK) return err;
p = tp.parms_out_buf;
}
SearchCount = Transact_getword(p); p += 2;
EndOfSearch = Transact_getword(p); p += 2;
if (EndOfSearch)
debug0(">> Server said it was the end of the search operation\n");
for (i = 0, p = tp.data_out_buf; i < SearchCount; i++, p += 27 + length + 1)
{
BYTE *fname = p + 27;
bool taken;
length = p[26];
if ( ((length == 1) && (fname[0] == '.') && (fname[1] == 0)) ||
((length == 2) && (fname[0] == '.') && (fname[1] == '.') && (fname[2] == 0)) )
{
continue;
}
taken = true; /* Store resume info if skipping files */
if (fnd->Offset >= fnd->Resume)
{
err = dirfn(p + 4, 1, &taken, dirfn_handle);
if (err != OK)
{
/* Entry expander must have run out of space! */
return EOUTOFMEM;
}
}
if (taken)
{
fnd->Offset++;
*dir_offset_out = SMBFind_SetOffset(fnd->Offset);
fnd->ResumeKey = Transact_getlong(p);
strncpy(fnd->FileName, (char*)fname, sizeof(fnd->FileName));
}
}
if (EndOfSearch || SearchCount == 0)
{
SMBFind_Close(fnd);
return ENOMOREFILES;
}
return OK;
}
/* Copyright 2020 RISC OS Open Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SMBFIND_H
#define SMBFIND_H
typedef struct SMBFind_t
{
DWORD Resume;
DWORD Offset;
hSHARE hS;
char ROPath[256];
WORD SID;
DWORD ResumeKey;
char FileName[DOS_NAME_LEN];
} SMBFind_t;
err_t SMBFind_EnumDir(SMBFind_t *fnd, int dir_offset, const char* ro_path, int count,
ENUM_DIR_FN dirfn, void *dirfn_handle,
int *dir_offset_out);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment