TalAloni / SMBLibrary

Free, Open Source, User-Mode SMB 1.0/CIFS, SMB 2.0, SMB 2.1 and SMB 3.0 server and client library
GNU Lesser General Public License v3.0
712 stars 182 forks source link

Trying to get information from subfolders with smb1 client #78

Closed Pfannaa closed 3 years ago

Pfannaa commented 3 years ago

Hi @TalAloni

Older post for reference: https://github.com/TalAloni/SMBLibrary/issues/9#issuecomment-376871908_

My problem is, i always get the root directorys information. From what i've unterstood. I need to create a handle to the subfolder i want to access. This works fine with SMBv2, but i just don't get how i need to pass the argument in the CreateFile Method with my smb1 client. What confuses me though: I can't pass the handle into the CreateFile method..

My Code:

 ISMBFileStore fileStore = _smbClient.TreeConnect("C$", out status);

            if (status == NTStatus.STATUS_SUCCESS)
            {
                object dirHandle;
                FileStatus fileStatus;

                // SMBClient is SMB1
                if (!_isSMBV2)
                {
                    status = fileStore.CreateFile(out dirHandle, out fileStatus, "\\", AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);

                    if (status == NTStatus.STATUS_SUCCESS)
                    {
                        status = ((SMB1FileStore)fileStore).QueryDirectory(out fileListSMB1, "\\*", FindInformationLevel.SMB_FIND_FILE_FULL_DIRECTORY_INFO);
                        status = fileStore.CloseFile(dirHandle);

                        foreach (FindInformation file in fileListSMB1)
                        {
                            //File remoteFile = new File(((SMBLibrary.SMB1.FindFileDirectoryInfo)file).FileName.ToString(), ((SMBLibrary.SMB1.FindFileDirectoryInfo)file).FileIndex);

                            string fileName = ((SMBLibrary.SMB1.FindFileFullDirectoryInfo)file).FileName.ToString();
                            ReturnableFileList.Add(fileName);
                        }
                    }
                }

// SMBClient is SMB2
                else if (_isSMBV2)
                {
                    status = fileStore.CreateFile(out dirHandle, out fileStatus, "Temp", AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);

                    if (status == NTStatus.STATUS_SUCCESS)
                    {
                        status = ((SMB2FileStore)fileStore).QueryDirectory(out fileListSMB2, dirHandle, "*", FileInformationClass.FileDirectoryInformation);
                        status = fileStore.CloseFile(dirHandle);

                        foreach (QueryDirectoryFileInformation file in fileListSMB2)
                        {

                            //File remoteFile = new File(((SMBLibrary.FileDirectoryInformation)file).FileName.ToString(), ((SMBLibrary.FileDirectoryInformation)file).FileIndex);

                            string fileName = ((SMBLibrary.FileDirectoryInformation)file).FileName.ToString();
                            ReturnableFileList.Add(fileName);

                            //((SMBLibrary.FileDirectoryInformation)file).FileName.ToString();
                        }
                    }
                }
TalAloni commented 3 years ago

CreateFile should be used to obtain the handle to the subdirectory you want to query. (e.g. '\Temp') QueryDirectory should specify the filter within the directory.

Pfannaa commented 3 years ago

Yeah i get the idea, although.. If you are using an SMB1FileStore, it doesn't let you pass in the handle. As seen as in my screenshot. cantpasshandle

Which means, i always get the root directories info. Doesn't matter which path i pass in.

If i try to pass in the handle like this:

if (!_isSMBV2)
                {
                    status = fileStore.CreateFile(out dirHandle, out fileStatus, @"\Temp", AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);

                    if (status == NTStatus.STATUS_SUCCESS)
                    {
                        status = ((SMB1FileStore)fileStore).QueryDirectory(out fileListSMB1, dirHandle, "\\*", FileInformationClass.FileFullDirectoryInformation);
                        status = fileStore.CloseFile(dirHandle);

                        foreach (var file in fileListSMB1)
                        {                           

                            string fileName = ((SMBLibrary.FileFullDirectoryInformation)file).FileName.ToString();
                            ReturnableFileList.Add(fileName);
                        }
                    }
                }

I always get a NotImplementedException at the QueryDirectory call

And now i know why :) --> image

I guess i need to format the path in a different way (i tried "\temp" and various other constellations). Could you please provide the correct formatting ?

TalAloni commented 3 years ago

Sorry, for SMB1 QueryDirectory accepts the path relative to the share, for example: status = ((SMB1FileStore)fileStore).QueryDirectory(out fileList2, "\\Trip\\*", FindInformationLevel.SMB_FIND_FILE_DIRECTORY_INFO); (When "Trip" is the name of the folder insider the share)

Pfannaa commented 3 years ago

Thank you so much! Working like a charm.

Shashichanti commented 5 months ago

hi @TalAloni , i want to access the file from my shared folder \Servever\ROOT\Useruploaded \2024\3\29\Data.pdf

IPAddress iPAddress = IPAddress.Parse(server);

// Connect to the SMB server SMB2Client client = new SMB2Client(); bool isConnected = client.Connect(iPAddress, SMBTransportType.DirectTCPTransport); // Connect to the share NTStatus status1; if (isConnected) { List shares = new List(); // Authenticate with the server NTStatus status = client.Login(string.Empty, username, password); if (status != NTStatus.STATUS_SUCCESS) { throw new Exception($"Failed to connect to share: {status}"); } else if (status == NTStatus.STATUS_SUCCESS) { shares = client.ListShares(out status); }

ISMBFileStore fileStore = client.TreeConnect("Root", out status);
if (status == NTStatus.STATUS_SUCCESS)
{
    object directoryHandle;
    FileStatus fileStatus;
    status = fileStore.CreateFile(out directoryHandle, out fileStatus, @"\ Useruploaded \2024\3\29\Data.pdf", AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
    status = fileStore.CreateFile(out directoryHandle, out fileStatus, "\\", AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
    if (status == NTStatus.STATUS_SUCCESS)
    {
        List<FindInformation> fileList2;
        status = ((SMB1FileStore)fileStore).QueryDirectory(out fileList2, "\\*", FindInformationLevel.SMB_FIND_FILE_DIRECTORY_INFO);
        //status=fileStore1.QueryDirectory(out fileList2, "\\*", FindInformationLevel.SMB_FIND_FILE_DIRECTORY_INFO);
        //status = fileStore.CloseFile(directoryHandle);
    }

    //object directoryHandle;
    //FileStatus fileStatus;
    status = fileStore.CreateFile(out directoryHandle, out fileStatus, String.Empty, AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
    if (status == NTStatus.STATUS_SUCCESS)
    {
        List<QueryDirectoryFileInformation> fileList;
        List<QueryFileAllInfo> fileList2;
        status = fileStore.QueryDirectory(out fileList, directoryHandle, "*", FileInformationClass.FileDirectoryInformation);
        foreach (FileDirectoryInformation file in fileList)
        {
            Console.WriteLine($"Filename: {file.FileName}");
            Console.WriteLine($"File Size: {file.AllocationSize / 1024}KB");
            Console.WriteLine($"Created Date: {file.CreationTime.ToString("f")}");
            Console.WriteLine($"Last Modified Date: {file.LastWriteTime.ToString("f")}");
            Console.WriteLine();
            Console.WriteLine();
        }
        //status=fileStore.GetFileInformation(out FileInformation result, directoryHandle, FileInformationClass.fileinfo);
        status = fileStore.CloseFile(directoryHandle);
    }
}

But am getting the Exception as STATUS_INVALID_PARAMETER Can you please help how can we access the file From subfolders of Shared Root Folder

TalAloni commented 5 months ago

@Shashichanti if you do not know which parameters should be sent (which often happens for first-timers), I suggest you use WireShark to monitor the values sent by Windows clients and imitate that. BTW - it's weird that you call CreateFile twice in sequence without checking if the first call succeeded and without using the handle of the correct call - that's surely a bug. I'm too busy to help everybody with their buggy code - please figure it out or hire someone to help you.