streams and reading from locked files

Share your advanced PureBasic knowledge/code with the community.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

streams and reading from locked files

Post by blueznl »

fweil, think i fixed it...

Code: Select all

; purebasic survival guide - pb3.90 sp1
; streams_1.pb - 18.05.2004 ejn (blueznl)
; http://www.xs4all.nl/~bluez/datatalk/purebasic.htm
;
; - NOT FOR BEGINNERS !!!
; - only on nt / win2k / xp using ntfs
; - backupread_()
; - open and read locked files
; - enumerate nt streams in files
; - needs double support to work on large files (> 2 gb)
;

filename.s = "c:\test.txt" 
file_h = CreateFile_(@filename, #READ_CONTROL, 0, 0, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, 0) 
;
Debug "start"
;
If file_h = 0
  Debug "can't open"
  End
EndIf
;
*buffer = AllocateMemory(4096) 
*stream.WIN32_STREAM_ID = *buffer
;
context.l = 0
bytes_read.l = 0
;
Repeat
  ;
  z = BackupRead_(file_h, *buffer, 20, @bytes_read, 0, 1, @context)
  ;
  ; dunno why, but backupread() sometimes returns 1 when it should be zero?!? so check for the nr. of bytes as well
  ; 
  If bytes_read = 0
    z = 0
  EndIf
  ;
  If z <> 0
    ;
    n+1
    Debug ""
    Debug "stream "+Str(n)
    id = *stream\dwStreamID
    Debug "stream id "+Str( id )
    Select id
      Case #BACKUP_DATA
        Debug "data"
      Case #BACKUP_EA_DATA
        Debug "extended attribute"
      Case #BACKUP_SECURITY_DATA
        Debug "security data"
      Case #BACKUP_ALTERNATE_DATA
        Debug "alternate data"
      Case #BACKUP_LINK
        Debug "hard link information"
      Default
        Debug "unknown id type"
        z=0
    EndSelect
    ;
    If z <> 0
      ;
      Debug "stream attributes %"+Bin( *stream\dwStreamAttributes )
      ;
      size.l = *stream\dwStreamSizeLow + *stream\dwStreamSizeHigh *256*256*256*256
      namesize.l = *stream\dwStreamNameSize
      ;
      Debug "stream size "+Str(size)
      Debug "name size "+Str(namesize)
      ;
      If namesize > 0
        BackupRead_(file_h, *buffer, namesize, @bytes_read, 0, 1, @context)
        l = WideCharToMultiByte_(#CP_OEMCP,0,*buffer,-1,0,0,0,0) 
        name.s = Space(l) 
        l = WideCharToMultiByte_(#CP_OEMCP,0,*buffer,-1,@name,l,0,0) 
        Debug "name... "+Str(bytes_read)+" "+name
      EndIf
      If size > 0
        seeked_l.l = 0
        seeked_h.l = 0
        BackupSeek_(file_h, size, 0, @seeked_l.l, @seeked_h.l, @context)
        Debug "data..."+Str(seeked_l + seeked_h *256*256*256*256)
      EndIf
    EndIf
  EndIf
Until z = 0
;
BackupRead_(file_h, *buffer,0,@bytes_read,1,0,@context)
CloseHandle_(file_h)
;
Debug ""
Debug "done"
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

My sample above is NOT totally working. It is, sort of. Here's a little updated code, which should work better, but which does not yet handle 'locked' files well. Some more puzzling to do...

Code: Select all

; purebasic survival guide - pb4.02
; ntfs streams 1.pb - 01.11.2007 ejn (blueznl)
; http://www.xs4all.nl/~bluez/datatalk/purebasic.htm
;
; - NOT FOR BEGINNERS !!!
; - only on nt / win2k / xp using ntfs
; - bakcupread_()
; - open and read locked files (well, not yet...)
; - enumerate nt streams in files
; - obviously, you need to create a file that supports streams :-) this code does not create one...

filename.s = "c:\test.txt"
Debug "start"
;
; i can read al alternative streams from an open and locked file, using
;
; OpenFile(1,filename)
; file_h = CreateFile_(@filename, #READ_CONTROL, 0, 0, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, 0)
;
; but that won't help me reading the data from the primary (unnamed) stream!
; ... i guess i'll have to expand the above and include changing the rights of my process if i want
; to open locked files... but i don't know yet how to, any help appreciated!
;
; to open and read multiple streams from a normal file (that's not in use) use this:
;
file_h = CreateFile_(@filename, #GENERIC_READ, 0, 0, #OPEN_EXISTING, 0, 0)
;
If file_h = 0
  Debug "can't open"
  End
EndIf
;
context.l = 0
bytes_read.l = 0
seek_l = 0
seek_h = 0
;
Repeat
  ;
  *buffer = AllocateMemory(SizeOf(WIN32_STREAM_ID))
  *stream.WIN32_STREAM_ID = *buffer
  z = BackupRead_(file_h, *buffer, 20, @bytes_read, 0, 1, @context)
  ;
  n = n+1
  Debug ""
  Debug "stream "+Str(n)
  Debug "bytes read "+Str(bytes_read)
  id = *stream\dwStreamID
  Debug "stream id "+Str(id)
  Select id
  Case #BACKUP_DATA
    Debug "data"
  Case #BACKUP_EA_DATA
    Debug "extended attribute"
  Case #BACKUP_SECURITY_DATA
    Debug "security data"
  Case #BACKUP_ALTERNATE_DATA
    Debug "alternate data"
  Case #BACKUP_LINK
    Debug "hard link information"
  Default
    Debug "unknown id type"
    z=0
  EndSelect
  Debug "stream attributes %"+Bin( *stream\dwStreamAttributes )
  streamsize.l = *stream\dwStreamSizeLow + *stream\dwStreamSizeHigh *256*256*256*256
  Debug "stream size "+Str(streamsize)
  namesize.l = *stream\dwStreamNameSize
  Debug "name size "+Str(namesize)
  FreeMemory(*buffer)
  ;
  If namesize > 0
    *buffer = AllocateMemory(namesize+SizeOf(WIN32_STREAM_ID))
    BackupRead_(file_h,*buffer,namesize,@bytes_read,0,1,@context)
    l = WideCharToMultiByte_(#CP_OEMCP,0,*buffer,-1,0,0,0,0)
    name.s = Space(l)
    l = WideCharToMultiByte_(#CP_OEMCP,0,*buffer,-1,@name,l,0,0)
    Debug "name "+name+" ("+Str(bytes_read)+")"
    FreeMemory(*buffer)
  EndIf
  ;
  If streamsize > 0
    *buffer = AllocateMemory(streamsize+SizeOf(WIN32_STREAM_ID))
    Debug BackupRead_(file_h,*buffer,streamsize,@bytes_read,0,1,@context)
    FreeMemory(*buffer)
    Debug "read "+Str(bytes_read)
  EndIf
  ;
  ; you have to use a BackupSeek_() to go to the next stream
  ;
  ; (strangely enough, you could bypass the BackupSeek_() if the streem has no data block but that's undocumented so always use BackupSeek_())
  ;
  BackupSeek_(file_h, streamsize, 0, @seek_l, @seek_h, @context)
  Debug "skipped "+Str(seek_l+seek_h*256*256*256*256)
  ;
Until z = 0
;
BackupRead_(file_h,0,0,@bytes_read,1,0,@context)
CloseHandle_(file_h)
;
Debug ""
Debug "done"
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Post by Mistrel »

Would you give an example of what kind of application this would be useful for?
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

Backup tools, log viewers, anti-virus, etc.
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Re: streams and reading from locked files

Post by akj »

@blueznl:

Thank you for that posting, which my searching missed.
It appears to be very useful and I will analyse it.

@Mistrel:

I was intending to use ADS for storing an application's historical debug output within the same file as the working data. This way the debugging information would be transparent to the user who would [for simplicity] see just one file only, but would still be available to me for analysis.

Further, I was contemplating storing user preferences (currently held in a .ini file) here also.

To be more specific, I was thinking of doing the above for my greatly modified version of Horst Schaeffer's PB date reminder program from http://home.mnet-online.de/horst.muc/win.htm so that a single .LST file holds all the data. I rely heavily on my modified version of this program for personal needs, and frequently 'improve' it.
Anthony Jordan
Nico
Enthusiast
Enthusiast
Posts: 274
Joined: Sun Jan 11, 2004 11:34 am
Location: France

Re: streams and reading from locked files

Post by Nico »

Don't work with directory, any solution?
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Re: streams and reading from locked files

Post by blueznl »

That depends. Streams are not supposed to be working with directories, they are part of files...
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
jpd
Enthusiast
Enthusiast
Posts: 167
Joined: Fri May 21, 2004 3:31 pm

Re: streams and reading from locked files

Post by jpd »

Hi,

@blueznl

thanks for this nice piece code.
Have use this some time ago in a project! :-)

@Nico
if you change the line

Code: Select all

file_h = CreateFile_(@filename, #GENERIC_READ, 0, 0, #OPEN_EXISTING, 0, 0)
with

Code: Select all

file_h = CreateFile_(@filename,#GENERIC_READ,#FILE_SHARE_READ, #Null, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, #Null)
then is possible to read stream on folder...

Best
jpd
PB 5.10 Windows 7 x64 SP1
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Re: streams and reading from locked files

Post by blueznl »

That's interesting, didn't know that streams could be put on folders. Oh well, the miracles of Windows :-)
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Nico
Enthusiast
Enthusiast
Posts: 274
Joined: Sun Jan 11, 2004 11:34 am
Location: France

Re: streams and reading from locked files

Post by Nico »

@jpd
Ok

@blueznl
Your code contains errors, I made a new version.
Compile to Unicode!

Code: Select all

; ---------------------------------------
; PureBasic 4.51
; Compile to Unicode
; Read Stream for file or directory
;----------------------------------------

filename.s = "C:\Documents And Settings\Nico\Bureau\Test.txt"
Debug "start"
;
; i can read al alternative streams from an open and locked file, using
file_h = CreateFile_(@filename, #READ_CONTROL, 0, 0, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, 0)


If file_h = 0
  Debug "can't open"
  End
EndIf
;
context.l = 0
bytes_read.l = 0
bytes_read1.l = 0
seek_l = 0
seek_h = 0
result.l=0

*stream.WIN32_STREAM_ID = AllocateMemory(20)
z = BackupRead_(file_h, *stream, 20, @bytes_read, 0, 1, @context)


While (bytes_read <> 0 )
  Debug ""
  n = n+1
  Debug "stream "+Str(n)
  Debug "bytes read "+Str(bytes_read)
  id = *stream\dwStreamID
  Debug "stream id "+Str(id)
  
  Select id
    Case #BACKUP_ALTERNATE_DATA ;0x00000004
      Debug "Alternative Data streams. This corresponds To the NTFS $DATA stream type on a named Data stream."
      
    Case #BACKUP_DATA ;0x00000001
      Debug "Standard Data. This corresponds To the NTFS $DATA stream type on the Default (unnamed) Data stream."
      
    Case #BACKUP_EA_DATA ;0x00000002
      Debug "Extended attribute Data. This corresponds To the NTFS $EA stream type."
      
    Case #BACKUP_LINK ;0x00000005
      Debug "Hard link information. This corresponds To the NTFS $FILE_NAME stream type."
      
    Case 7 ;#BACKUP_OBJECT_ID ;0x00000007
      Debug "Objects identifiers. This corresponds To the NTFS $OBJECT_ID stream type."
      
    Case 6 ;#BACKUP_PROPERTY_DATA ;0x00000006
      Debug "Property Data."
      
    Case 8 ;#BACKUP_REPARSE_DATA ;0x00000008
      Debug "Reparse points. This corresponds To the NTFS $REPARSE_POINT stream type."
      
    Case #BACKUP_SECURITY_DATA ;0x00000003
      Debug "Security descriptor Data."
      
    Case 9 ;#BACKUP_SPARSE_BLOCK ;0x00000009
      Debug "Sparse file. This corresponds To the NTFS $DATA stream type For a sparse file."
      
    Case 10 ;#BACKUP_TXFS_DATA ;0x0000000A
      Debug "Transactional NTFS (TxF) Data stream. This corresponds To the NTFS $TXF_DATA stream type."
  EndSelect
  ;
  namesize.l = *stream\dwStreamNameSize
  Debug "name size "+Str(namesize)
  If namesize > 0
    *buffer = AllocateMemory(namesize)
    BackupRead_(file_h,*buffer,namesize,@bytes_read1,0,1,@context)
    Debug PeekS(*buffer,namesize/2,#PB_Unicode)
    FreeMemory(*buffer)
  EndIf
  ;
  
  streamHight.q=*stream\dwStreamSizeHigh & $FFFFFFFF
  streamLow.q=*stream\dwStreamSizeLow & $FFFFFFFF
  streamsize.q =  streamHight<<32 |  streamLow
  Debug "streamsize="+Str(streamsize)
  ;
  
  result.l= BackupSeek_(file_h, *stream\dwStreamSizeLow, *stream\dwStreamSizeHigh, @seek_l, @seek_h, @context)
  Debug "Result="+Str(Result)
  ;
  FreeMemory(*stream)
  *stream.WIN32_STREAM_ID = AllocateMemory(20)
  bytes_read = 0
  z = BackupRead_(file_h, *stream, 20, @bytes_read, 0, 1, @context)
Wend 

FreeMemory(*stream)

BackupRead_(file_h,0,0,@bytes_read,1,0,@context)
CloseHandle_(file_h)
;
Debug ""
Debug "done" 
Post Reply