Sapere se un file di nome sconosciuto è stato creato o distrutto

Da Gambas-it.org - Wikipedia.

Può accadere che si voglia sapere se un qualsiasi file, del quale non è conosciuto a priori il nome, sia stato creato o distrutto all'interno di una determinata Cartella.


Per mostrare un primo esempio meramente dimostrativo, faremo l'esempio della immediata verifica della creazione nella cartella "/dev/pts" del file speciale di tipo pts di un Terminale nel momento in cui tale Terminale viene aperto:

Public Sub Form_Open()

 Dim b As Byte
 Dim ss As New String[]
 Dim s, dr As String
 
 dr = "/dev/pts"
 
' Assegna ad una variabile vettoriale il nome dei file presenti nella cartella "/dev/pts":
 b = Dir(dr, Null, gb.Device).Copy()

' Resta in attesa sino a quando un Terminale non è stato aperto:
 Repeat
   Wait 0.01
 Until Dir(dr, Null, gb.Device).Count = ss.Count + 1

' Effettua la verifica di quale file speciale di tipo "pts" corrisponde a quello del Terminale appena aperto:
' il nuovo file "pts", non presente nella variabile vettore di tipo stringa, è quello del Terminale:
 For Each s In Dir(dr, Null, gb.Device)
   If Not ss.Exist(s) Then Exit
 Next
   
 Print s

End


Verificare la creazione e/o la distruzione di un file

Per verificare se un elemento sia stato creato oppure distrutto, se già esistente, all'interno di una cartella, è possibile utilizzare almeno due modalità.

Uso della Classe Watch

La prima modalità prevede l'uso della Classe "Watch" mediante l'attivazione del Componente "gb.inotify".

Mostriamo un esempio pratico:

Private w As Watch


Public Sub Main()
 
 w = New Watch("/tmp") As "Cartella"
  
End


Public Sub Cartella_Create()
 
 Print "Creato: "; Watch.Name
 
End


Public Sub Cartella_Delete()
 
 Print "Distrutto: "; Watch.Name
 
End


Uso della Classe Timer

Quest'altra modalità prevede l'uso della Classe Timer per verificare la creazione e/o la distruzione di un file all'interno ad esempio della Cartella "/tmp". L'uso dell'oggetto Timer, ci consentirà di non chiudere il programma all'interno di un ciclo infinito.

Private tempus As Timer
Private ss As New String[]
Private dr As String


Public Sub Main()
 
 Dim b As Byte
 Dim ss As New String[]
  
 dr = "/tmp"
 ss = Dir(dr, Null, gb.File).Copy()
  
 With tempus = New Timer As "Tempus"
   .Delay = 100
   .Start
 End With
  
End


Public Sub Tempus_Timer()
 
 Dim b As Byte
 Dim s As String
 
 If ss.Count <> Dir(dr, Null, gb.File).Count Then
   For Each s In Dir(dr, Null, gb.File)
     If Not ss.Exist(s) Then
       Print "\nCreato il file: "; s
       ss = Dir(dr, Null, gb.File).Copy()
     Endif
   Next
   For Each s In ss
     If Not Exist(dr &/ s) Then
       Print "\nDistrutto il file: "; s
       ss = Dir(dr, Null, gb.File).Copy()
     Endif
   Next
 Endif
  
End


Uso delle risorse del API di inotify

E' possibile anche utilizzare le risorse inotify, dichiarate nel file header sys/inotify.h .
Va ricordato che vari pseudo-filesystem come "/proc", "/sys" e "/dev/pts" non sono monitorabili con inotify.

Mostriamo un esempio, nel quale si verificheranno la creazione e la distruzione di un determinato file mediante due Button:

Private Const BUFFER As Long = 4096
Private bo As Boolean


Library "libc:6"

Public Struct inotify_event
  wd As Integer
  mask As Integer
  cookie As Integer
  lenI As Integer
  name[32] As Byte
End Struct

Public Struct pollfd
  fd As Integer
  events As Short
  revents As Short
End Struct

Private Const IN_ACCESS As Integer = 1          ' File was accessed.
Private Const IN_MODIFY As Integer = 2          ' File was modified.
Private Const IN_ATTRIB As Integer = 4          ' Metadata changed.
Private Const IN_CLOSE_WRITE As Integer = 8     ' Writtable file was closed.
Private Const IN_CLOSE_NOWRITE As Integer = &10 ' Unwrittable file closed.
Private Const IN_OPEN As Integer = &20          ' File was opened.
Private Const IN_MOVED_FROM As Integer = &40    ' File was moved From X.
Private Const IN_MOVED_TO As Integer = &80      ' File was moved To Y.
Private Const IN_CREATE As Integer = &100       ' Subfile was created.
Private Const IN_DELETE As Integer = &200       ' Subfile was deleted.
Private Const IN_DELETE_SELF As Integer = &400  ' Self was deleted.
Private Const IN_MOVE_SELF As Integer = &800    ' Self was moved.
Private Const IN_UNMOUNT As Integer = &2000     ' Backing fs was unmounted.
Private Const IN_Q_OVERFLOW As Integer = &4000  ' Event queued overflowed.
Private Const IN_IGNORED As Integer = &8000     ' File was ignored.
Private Const IN_ISDIR As Integer = &40000000   ' Event occurred against dir.
Private Const IN_ALL_EVENTS As Integer = 4095

Private Const POLLIN As Short = 1

' int inotify_init (void)
' Create and initialize inotify instance.
Private Extern inotify_init() As Integer

' int inotify_add_watch (int __fd, const char *__name, uint32_t __mask)
' Add watch of object NAME to inotify instance FD.
Private Extern inotify_add_watch(__fd As Integer, name As String, __mask As Integer) As Integer

' int inotify_rm_watch (int __fd, int __wd)
' Remove the watch specified by WD from the inotify instance FD.
Private Extern inotify_rm_watch(__fd As Integer, __wd As Integer) As Integer

' int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
' Poll the file descriptors described by the NFDS structures starting at FDS.
Private Extern poll(__fds As Pollfd, __nfds As Long, __timeout As Integer) As Integer

' ssize_t read (int __fd, void *__buf, size_t __nbytes)
' Read NBYTES into BUF from FD.
Private Extern read_C(__fd As Integer, __buf As Pointer, __nbytes As Long) As Long Exec "read"

' int close (int __fd)
' Close the file descriptor FD.
Private Extern close_C(__fd As Integer) As Integer Exec "close"


Public Sub Form_Open()
 
 Dim percorso_file As String
 Dim fd, wa As Integer
 Dim buf, p As Pointer
 Dim letti As Long
 Dim evento As New Inotify_event
 Dim pl As New Pollfd
 
 Me.Show
  
'  == Poniamo sotto osservazione la Cartella "/tmp", qualora venga creato o venga distrutto un file ==
  
 percorso_file = "/tmp"
   
 fd = inotify_init()
 If fd = -1 Then Error.Raise("Impossibile inizializare 'inotify' !")
   
 wa = inotify_add_watch(fd, percorso_file, IN_ALL_EVENTS)
 If wa = -1 Then Error.Raise("Errore alla funzione esterna 'inotify_add_watch()' !")
   
 Print "Cartella '"; percorso_file; "' ...sotto osservazione !\n"
   
 buf = Alloc(CInt(BUFFER))
  
 While bo = False    
   pl.fd = fd
   pl.events = POLLIN
   letti = poll(pl, 1, 100)
   Select Case letti
     Case -1
       Error.Raise("Errore alla funzione esterna 'poll()' !")
     Case 1
       letti = read_C(fd, buf, BUFFER)
       If letti = -1 Then Error.Raise("Errore alla funzione esterna 'read_C()' !")
   End Select
   p = buf
   While p < buf + CInt(letti)
     evento = p
     If evento.mask And IN_CREATE Then Print "Creato il nuevo file: "; String@(evento.name.Data)
     If evento.mask And IN_DELETE Then Print "Eliminato il file: "; String@(evento.name.Data)
     If evento.mask And IN_MOVED_FROM Then Print "Spostato nel cestino il file: "; String@(evento.name.Data)
     p += 16 + evento.lenI
   Wend
   Wait 0.1
 Wend
   
' Libera memoria in chiusura:
 Free(buf)
 inotify_rm_watch(fd, wa)
 close_C(fd)
 Me.Close
  
End


Public Sub Button1_Click()
  
' Va in chiusura...
 bo = True
     
End

Il precedente codice può essere ovviamente inserito - con le dovute variazioni - anche in un'applicazione a riga di comando:

Private Const BUFFER As Long = 4096
Private bo As Boolean


Library "libc:6"

Public Struct inotify_event
  wd As Integer
  mask As Integer
  cookie As Integer
  lenI As Integer
  name[32] As Byte
End Struct

Public Struct pollfd
  fd As Integer
  events As Short
  revents As Short
End Struct

Private Const IN_ACCESS As Integer = 1          ' File was accessed.
Private Const IN_MODIFY As Integer = 2          ' File was modified.
Private Const IN_ATTRIB As Integer = 4          ' Metadata changed.
Private Const IN_CLOSE_WRITE As Integer = 8     ' Writtable file was closed.
Private Const IN_CLOSE_NOWRITE As Integer = &10 ' Unwrittable file closed.
Private Const IN_OPEN As Integer = &20          ' File was opened.
Private Const IN_MOVED_FROM As Integer = &40    ' File was moved From X.
Private Const IN_MOVED_TO As Integer = &80      ' File was moved To Y.
Private Const IN_CREATE As Integer = &100       ' Subfile was created.
Private Const IN_DELETE As Integer = &200       ' Subfile was deleted.
Private Const IN_DELETE_SELF As Integer = &400  ' Self was deleted.
Private Const IN_MOVE_SELF As Integer = &800    ' Self was moved.
Private Const IN_UNMOUNT As Integer = &2000     ' Backing fs was unmounted.
Private Const IN_Q_OVERFLOW As Integer = &4000  ' Event queued overflowed.
Private Const IN_IGNORED As Integer = &8000     ' File was ignored.
Private Const IN_ISDIR As Integer = &40000000   ' Event occurred against dir.
Private Const IN_ALL_EVENTS As Integer = 4095

Private Const POLLIN As Short = 1

' int inotify_init (void)
' Create and initialize inotify instance.
Private Extern inotify_init() As Integer

' int inotify_add_watch (int __fd, const char *__name, uint32_t __mask)
' Add watch of object NAME to inotify instance FD.
Private Extern inotify_add_watch(__fd As Integer, name As String, __mask As Integer) As Integer

' int inotify_rm_watch (int __fd, int __wd)
' Remove the watch specified by WD from the inotify instance FD.
Private Extern inotify_rm_watch(__fd As Integer, __wd As Integer) As Integer

' int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
' Poll the file descriptors described by the NFDS structures starting at FDS.
Private Extern poll(__fds As Pollfd, __nfds As Long, __timeout As Integer) As Integer

' ssize_t read (int __fd, void *__buf, size_t __nbytes)
' Read NBYTES into BUF from FD.
Private Extern read_C(__fd As Integer, __buf As Pointer, __nbytes As Long) As Long Exec "read"

' int close (int __fd)
' Close the file descriptor FD.
Private Extern close_C(__fd As Integer) As Integer Exec "close"


Public Sub Main()
 
 Dim percorso_file As String
 Dim fd, wa As Integer
 Dim buf, p As Pointer
 Dim letti As Long
 Dim evento As New Inotify_event
 Dim pl As New Pollfd
  
'  == Poniamo sotto osservazione la Cartella "/tmp", qualora venga creato o venga distrutto un file ==
  
 percorso_file = "/tmp"
   
 fd = inotify_init()
 If fd = -1 Then Error.Raise("Impossibile inizializare 'inotify' !")
   
 wa = inotify_add_watch(fd, percorso_file, IN_ALL_EVENTS)
 If wa = -1 Then Error.Raise("Errore alla funzione esterna 'inotify_add_watch()' !")
   
 Print "Cartella '"; percorso_file; "' ...sotto osservazione !\n"
   
 buf = Alloc(CInt(BUFFER))
  
 While bo = False
   pl.fd = fd
   pl.events = POLLIN
   letti = poll(pl, 1, 100)
   Select Case letti
     Case -1
       Error.Raise("Errore alla funzione esterna 'poll()' !")
     Case 1
       letti = read_C(fd, buf, BUFFER)
       If letti = -1 Then Error.Raise("Errore alla funzione esterna 'read_C()' !")
   End Select
   p = buf
   While p < buf + CInt(letti)
     evento = p
     If evento.mask And IN_CREATE Then Print "Creato il nuevo file: "; String@(evento.name.Data)
     If evento.mask And IN_DELETE Then Print "Eliminato il file: "; String@(evento.name.Data)
     If evento.mask And IN_MOVED_FROM Then Print "Spostato nel cestino il file: "; String@(evento.name.Data)
     p += 16 + evento.lenI
   Wend
   Wait 0.1
 Wend
   
' Libera memoria in chiusura:
 Free(buf)
 inotify_rm_watch(fd, wa)
 close_C(fd)
 Quit
  
End


Public Sub Application_Read()
  
' Se si pone il puntatore del mouse nello spazio al di sotto della console e si preme il tasto "Invio" della tastiera, allora il programma va in chiusura...
 bo = True
     
End