No announcement yet.

How to get physical drive from a path ?

  • Filter
  • Time
  • Show
Clear All
new posts

  • How to get physical drive from a path ?

    For the junction points I need to know if two given paths (junction point's "mount path" and its target path) are located within a same physical drive. Please, tell me how I should do this, if using extra dlls is not preferred ?

    cheers.. aSa C[_]

  • #2
    A little clarification...

    I'm not sure what you mean by "the same physical drive". Do you mean within the same partition or between partitions? If you're tring to figure out if this is what you mean:


    here's what I'd do. In MS-DOS, it's easy to get the current drive using an Int 21h, like this:

    FUNCTION GetCurrentDrive$ PUBLIC
    REG 1?, &H1900
    GetCurrentDrive$ = CHR$((REG(1?) MOD &H0100) + &H41) + ":"
    This returns "A:", "B:", etc. Next, I'd write:

    SourcePath$ = GetCurrentDrive$ + SourcePath$
    DestinationPath$ = GetCurrentDrive$ + DestinationPath$
    Now both are full-blown filespecs. Next, I'd open my AUTOEXEC.BAT file and scan for any SUBST commands and do:

    REPLACE FakeDrive$ WITH SubstitutedPath$ IN SourcePath$
    REPLACE FakeDrive$ WITH SubstitutedPath$ IN DestinationPath$

    You should be able to scan the paths to see if they're valid. If the drive letters still don't match (path not found), then the two paths are on different drives (physical or logical (different partition)). I hope this helps.


    • #3
      Well, if I'm given two paths, I would like to know if they are located within one physical hard drive. One drive can contain multiple partitions, as you well know. So the paths may be in different partitions, but still in one drive.

      I don't know how to explain this more clearly, I'm sorry.

      Maybe this is just too difficult to achieve with my skills, so I'll start looking some other ways to deal with this.

      cheers.. aSa C[_]


      • #4
        I'm a bit stuck on your use of the term "junction point". I have never gotten into the depths of the NTFS, but I gather that directory structures can be "grafted" (not sure if that's a technical term) to each other by means of "junction points". (I know that Unix used to allow such mounting points almost anywhere... don't think MS OS do.)

        Are you using the term in this technical sense? If so, that's as much help as I can offer at this time.

        As MCM will eventually ask: "Please describe the task that you are trying to accomplish." (I mention this because I don't understand why you'd be concerned about things being on the same PHYSICAL drive - doesn't the file system handle all mounting issues?)


        • #5
          The following isn't compileable code straight off the bat, but it should point you in the right direction. How this is affected by remote mounting of volumes into a directory structure of an existing volume, I do not know as I haven't tested.

          GetFileInformationByHandle() works from W95 and up.

          There is also a GetFileInformationByHandleEx() function that that yields complementing details rather than just more details as I fail to find that any volume info can be retrieved. This variant is natively available from Windows Vista/Windows Server2008 but may also exist on some XP and Windows Server 2003 systems as it is redistributable from the Windows SDK. In practice this would be dependant on the applications installed, but also that you are allowed to distribute it yourself with your XP/Server 2003 applications.

            LOCAL lpFileInformation AS BY_HANDLE_FILE_INFORMATION
            LOCAL hFile AS DWORD
            lFNum = FREEFILE  
            OPEN yourfile FOR INPUT ACCESS READ as lFNum
            hFile = FILEATTR( # lFNum, 2) ' Get the file's OS file-handle
            lFuncRet = GetFileInformationByHandle (BYVAL hFile, lpFileInformation)
            lVolume = lpFileInformation.dwVolumeSerialNumber ' This determines the volume the file belongs to.
                                                             ' Which means a logical primary or part of a secondary partition or on
                                                             ' another physical disk. On its own, it cannot determine which partition or
                                                             ' which physical disk.
            CLOSE # lFNum
          ' From Win32.hlp, in the part describing the BY_HANDLE_FILE_INFORMATION structure:
          '    nFileIndexHigh = Specifies the high-order word of a unique identifier associated with the file. 
          '    nFileIndexLow  = Specifies the low-order word of a unique identifier associated with the file. 
          '                     This identifier and the volume serial number uniquely identify a file. This 
          '                     number may change when the system is restarted or when the file is opened. 
          '                     After a process opens a file, the identifier is constant until the file is 
          '                     closed. An application can use this identifier and the volume serial number 
          '                     to determine whether two handles refer to the same file. 
          ' MSDN online has complementing info that should be considered as well, but since the online MSDN do not
          ' support W95 any more, only W2000 and up is said to be supported.


          • #6
            Sorry Ari, missed your stating physical disks, I was concerned about volumes. So the suggestion above does not apply.

            However, if you follow this link, it should give a solution:

            Exerpt from the link:
            Detecting the Type of Disk
            There is no specific function to programmatically detect the type of disk a particular file or directory is located on. There is an indirect method.

            First, call GetVolumePathName. Then, call CreateFile to open the volume using the path. Next, use IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS with the volume handle to obtain the disk number and use the disk number to construct the disk path, such as "\\?\PhysicalDriveX". Finally, use IOCTL_DISK_GET_DRIVE_LAYOUT_EX to obtain the partition list, and check the PartitionType for each entry in the partition list.

            The Partition info from the last call also holds the disk's signature which can be used to identify the physical disk.

            As can be seen from the text in the link, there is a very high probability that Ari's junction points, John's grafts and my remote mounting are several names for the the same mechanism.



            • #7
              I am amiss about "Junction Points" (best guess is to do with COM/ACTIVEX/OCX)

              Unless I am wrong is the point really that you are trying to find a drive and path from your results??? (Code really needs to be shown for the question)
              Engineer's Motto: If it aint broke take it apart and fix it

              "If at 1st you don't succeed... call it version 1.0"

              "Half of Programming is coding"....."The other 90% is DEBUGGING"

              "Document my code????" .... "WHYYY??? do you think they call it CODE? "


              • #8
                The way I read Ari, is that he want to determine whether two files are located on the same physical drive or not (and maybe identify which physical drives as well), and that it is not sufficient to determine whether they exist in different partitions (in which case my first answer should suffice) since two partitions may exist on the same physical drive.
                This is due to the fact that it is possible to mount a logical volume into a directory at some point (aka "junction point") of another logical volume, and so making the two logical volumes look like the same (physical) disk although they aren't. E.g. you could mount E:\ at C:\Company\Sales\UsersVolumes, and so make E:\Paulsdata\Secret appear as C:\Company\Sales\UsersVolumes\Paulsdata\Secret.

                So the question is do C:\Company\Sales\UsersVolumes\Paulsdata\Secret reside on the same physical disk as do e.g. C:\Company\Directors\UsersVolumes?

                My response in #6 above suggests a method to resolve that.



                • #9
                  Actually NTFS is capable of doing *similar* tricks as *nix does, but they are not well supported by OS's themselves. Clarifying (MSDN) example about NTFS hardlinks and junctions. (Maybe Junction Point is a wrong term and I should start calling them Reparse Points or just Junctions ?? Although others are using the term Junction Point too)

                  This article has some "Windows methods" nicely collected together. With programming samples (C++).

                  Actually finding a drive and path is not necessary, all I want to know if the "targets" are pointing to locations that are within one drive.

                  Also I'm not so sure anymore if there really is that physical limitation. I don't remember where I read about that. Let's say that I think there may be such a limitation with Junctions. At least network drives/paths cannot be "Junctioned".

                  yes, that may be one possible direction to start digging, thank you. Like if partitions that contains the paths are with same drive or something.

                  cheers.. aSa C[_]


                  • #10
                    What about the WinApi GetCurrentDirectory function?
                    #COMPILE EXE
                    #DIM ALL
                    DECLARE FUNCTION GetCurrentDirectory LIB "KERNEL32.DLL" ALIAS "GetCurrentDirectoryA" (BYVAL nBufferLength AS LONG, lpBuffer AS ASCIIZ) AS LONG
                    FUNCTION PBMAIN () AS LONG
                      LOCAL iLoc AS LONG, szFolder AS ASCIIZ * 256
                      LOCAL sDrive AS STRING
                        IF GetCurrentDirectory(256, szFolder) THEN
                          sDrive = REMOVE$(szFolder, CHR$(0))
                          iLoc = INSTR(sDrive, ":")
                          sDrive = LEFT$(sDrive, iLoc)
                          MSGBOX "Cannot find current directory", 48, "Error!"
                          EXIT FUNCTION
                        END IF
                        MSGBOX sDrive, 64, "Get current drive..."
                    END FUNCTION

                    Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
                    *** Opinions expressed here are not necessarily untrue ***


                    • #11
                      Sorry folks. My above snippet gets a drive letter, which is not necessarily a physical drive. It might be a partition as well, so it's not what Ari is looking for.

                      Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
                      *** Opinions expressed here are not necessarily untrue ***


                      • #12
                        Ari, I'll look into the articles over the next day or two.

                        But meanwhile, I am unclear about the need that is at the root of this investigation: What is the problem that you are trying to solve? IOW, TO WHAT GOAL is it important that you determine if 2 paths or files are on the same physical drive?

                        We can't give you pointers on HOW to do it, if we're not clear about WHAT you're trying to do and WHY - it may or may not even be possible! How are we to tell??

                        There are so many different ways for a file system to be overlaid onto physical drives (not to mention intermediate partitions, etc.) that it is important for you to give us more information.

                        Consider for example, a file that is written to a server which is using RAID, an array of drives. In some RAID architectures, PARTS of files are stored on different physical drives. I know I'm not doing justice to these complex architectures, so anyone who can fill in a bit more detail, please do so.

                        My point is that the OS may not even be aware of the physical structures over which its file system is overlaid. And if the OS can't tell and doesn't concern itself about it, why would you?



                        • #13
                          thank you for your dedication. It's really hard to explain or ask things that I don't understand thoroughly. And don't know the right words/terms.. I hope you know the feeling.

                          The problem may not even exist (I have to test this scenario by myself some day). I just saw some code snippets that had included the drive check for some reason I haven't been able to verify yet.

                          I think you're thinking now a little too deep (about raids and all). Well, my bad, I guess. It's how NTFS sees things and what the specs for junctions says (if I will understand them correctly eventually). I'm sorry if I'm troubling (too much ) or something.

                          (some time passes here..)

                          A-ha. Found a possible source of the problem while desperately googling around. MSDN article about HARDLINKS (not about the "softlinks" I'm looking after.. ). Hardlinks are file based links and softlinks are folder based, if I remember right and simply enough.

                          There is the need for the drive check. "hard links must be created within the same NTFS volume".. volume.. hmm. One physical drive drive may contain several NTFS volumes, right? One partition is one volume? But anyway I'm not after hardlinks, so who cares..

                          "a junction can link directories located on different local volumes on the same computer." Junction docs says nothing about multiple physical drives, so that may not be a problem then. But I will test this with two drives, when I have the opportunity.

                          I'll dig more when time comes (I don't get paid for programming these things so I don't have to hurry with this).

                          I'm sorry for being so vague (hope thats the word ). I seem to got lost somewhere and started mixing stuff. Again.

                          cheers.. aSa C[_]


                          • #14
                            I actually DO understand how it feels to not be able to express the problem, so no sweat. At least now, I understand how you got into this particular inquiry.

                            Here's something else I came across, and thought you might find it useful.


                            I hope it helps. Also, the topics below it may also be relevant.

                            Last edited by John Montenigro; 23 Dec 2008, 04:37 PM.


                            • #15
                              If you use Win200x, XP, or (presumably) Vista and have at least one NTFS partition mounted, you can easily try this for yourself.

                              First make a directory on your NTFS partition (I will assume C.
                              md C:\CDROMdrive

                              Now open your Control Panel, choose Administrative tools, choose Computer Management, choose Disk Management.

                              Right-click on your CD/DVD drive (it doesn't have to have a CD inside yet) and choose Change Drive Letter and Paths.... Click the Add... button. Choose Mount in the following empty NTFS folder and then enter C:\CDROMdrive (or whatever you used) and OK it.

                              Wait a few seconds and put a data CD in. Stop the autoplay with the SHIFT key.

                              Now you should be able to
                              dir Q:\ (or whatever drive letter you use)
                              dir C:\CDROMdrive
                              and see the same results.

                              So now, going back to the original problem, you can see that a file in C:\CDROMdrive is not on the C: drive despite having a C:-based path. So the question is how would you trace that path back to CDROM0 in a PBCC/PBWin application. Once you know that, there is presumably some way to enumerate all letters and paths associated with that drive.
                              Last edited by Erich Schulman; 23 Dec 2008, 11:48 PM. Reason: disable smilies - doh!
                              Erich Schulman (KT4VOL/KTN4CA)
                              Go Big Orange


                              • #16

                                I do not have PowerBasic code for that, but I did similar in VB once using the following code:

                                Sub MappedDrivePartititions()
                                    Dim ComputerName As String
                                    Dim wmiServices As Object
                                    Dim objWMIService As Object
                                    Dim wmiDiskDrives As Object
                                    Dim wmiDiskDrive As Object
                                    Dim strEscapedDeviceID As String
                                    Dim wmiDiskPartitions As Object
                                    Dim wmiDiskPartition As Object
                                    Dim sOut As String
                                    Dim wmiLogicalDisks As Object
                                    Dim errResult As Variant
                                    Dim wmiLogicalDisk As Object
                                    On Error GoTo errSub
                                    ComputerName = "."
                                    Set wmiServices = GetObject( _
                                        "winmgmts:{impersonationLevel=Impersonate}!//" _
                                        & ComputerName)
                                    ' Get physical disk drive
                                    Set wmiDiskDrives = wmiServices.ExecQuery( _
                                        "SELECT Caption, DeviceID FROM Win32_DiskDrive")
                                    For Each wmiDiskDrive In wmiDiskDrives
                                        sOut = sOut & "Disk drive Caption: " _
                                            & wmiDiskDrive.Caption _
                                            & vbCrLf & "DeviceID: " _
                                            & " (" & wmiDiskDrive.DeviceID & ")" & vbCrLf
                                        'Backslash in disk drive deviceid
                                        ' must be escaped by "\"
                                        strEscapedDeviceID = Replace( _
                                            wmiDiskDrive.DeviceID, "\", "\\", _
                                            1, -1, vbTextCompare)
                                        'Use the disk drive device id to
                                        ' find associated partition
                                        Set wmiDiskPartitions = wmiServices.ExecQuery("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & strEscapedDeviceID & """} WHERE  AssocClass = Win32_DiskDriveToDiskPartition")
                                        For Each wmiDiskPartition In wmiDiskPartitions
                                            'Use partition device id to find logical disk
                                            Set wmiLogicalDisks = wmiServices.ExecQuery("ASSOCIATORS OF " & "{Win32_DiskPartition.DeviceID=""" & wmiDiskPartition.DeviceID & """} WHERE AssocClass = Win32_LogicalDiskToPartition")
                                            For Each wmiLogicalDisk In wmiLogicalDisks
                                                sOut = sOut & "Drive letter associated" _
                                                    & " with disk drive = " _
                                                    & wmiDiskDrive.Caption _
                                                    & wmiDiskDrive.DeviceID _
                                                    & vbNewLine & " Partition = " _
                                                    & wmiDiskPartition.DeviceID _
                                                    & vbNewLine & " is " _
                                                    & wmiLogicalDisk.DeviceID & vbCrLf & vbCrLf
                                    MsgBox sOut
                                    Exit Sub
                                    MsgBox Err.Description
                                End Sub
                                I think you can easily translate it to PB. The result will be something like that

                                Disk drive Caption: ST3808110AS
                                DeviceID: (\\.\PHYSICALDRIVE0)
                                Drive letter associated with disk drive = ST3808110AS\\.\PHYSICALDRIVE0
                                Partition = Disk #0, Partition #1
                                is C:

                                Disk drive Caption: WD 1600BEV External USB Device
                                DeviceID: (\\.\PHYSICALDRIVE1)
                                Drive letter associated with disk drive = WD 1600BEV External USB Device\\.\PHYSICALDRIVE1
                                Partition = Disk #1, Partition #0
                                is E:


                                Peter Redei


                                • #17
                                  Has anybody already translated the above code to PB? I'm not really sure how, haven't had success yet...
                                  I can enumerate Physical disks and Logical disks, but I need to connect them...

                                  "Simplicity is a prerequisite for reliability"


                                  • #18
                                    #Compile Exe
                                    #Dim All
                                    #Include ""
                                    Function PBMain () As Long
                                        Local szDevName, szResult As Asciiz * %MAX_PATH
                                        Local nResult As Dword
                                        szDevName = "C:"
                                        ' requires Windows 2000 or later
                                        nResult = QueryDosDevice(szDevName, szResult, SizeOf(szResult))
                                        StdOut Format$(nResult) + " " + szResult
                                    End Function


                                    • #19
                                      Thanks Tom,

                                      But that gives me: \device\harddisk6\dp(1)0+0+26
                                      instead of: \\.\PHYSICALDRIVE6 (that's the name Win32_DiskDrive returns...)

                                      "Simplicity is a prerequisite for reliability"


                                      • #20
                                        I believe the \\.\ method no longer works with the newer operating systems, so you may want to look into that.