Chris, thanks for that routine.

Although I have solved the current task without it you routine looked
interesting and potentially quite useful so I thought I would test it out a
bit further.  I found it necessary to make a couple of changes:
1). Impersonate Administrator user & then reset to normal user when
complete.
2). Create a SyncErr cursor to record failures.
3). Test if each action is successful, else write to aforementioned cursor.
4). Record file/directory attributes so we can establish which are read-only
when updating or deleting.
5). Remove read-only attribute when necessary.

Outstanding problem:
If a directory is to be deleted and the files in it are read-only then:
DELETE FILE *.* in AGRD() fails.  Need to find a way to either remove
read-only attrib from all files in a directory or loop through all files
removing it one by one.

Regards,
        Nick


New updated but untidy code below:

* Impersonate user code from the Fox Wiki by Hugo Ranea
#define LOGON32_PROVIDER_DEFAULT 0
#define LOGON32_LOGON_INTERACTIVE 2
#define LOGON32_LOGON_NETWORK 3
#define LOGON32_LOGON_BATCH 4
#define LOGON32_LOGON_SERVICE 5
#define LOGON32_LOGON_UNLOCK 7

DECLARE integer LogonUser IN AdvApi32.DLL;
 string szUsername,;
 string lpszDomain,;
   string lpszPassword,;
 integer dwLogonType,;
 integer dwLogonProvider,;
 integer @phToken

DECLARE integer ImpersonateLoggedOnUser IN AdvApi32.DLL integer hToken
DECLARE integer RevertToSelf IN AdvApi32.DLL

CLEAR

local nToken
nToken = 0
?
LogonUser("Administrator","MyServer","NotMyAdminPassword:)",LOGON32_LOGON_IN
TERACTIVE, LOGON32_PROVIDER_DEFAULT, @nToken)
? nToken

? ImpersonateLoggedOnUser(nToken)

CREATE CURSOR SyncErr (ctype c(1),csource m(10),ccopy m(10),cAttribs c(6))

SET ESCAPE ON
SET MESSAGE TO

DO Sync WITH "C:\Data", "D:\Archive"

? RevertToSelf()

RETURN


PROCEDURE Sync
LPARAMETERS lcsource,lccopy

? "Syncronising: ",lcsource," to ",lccopy," - "

LOCAL lcreturn,llreturn

llreturn=.t.
lcreturn=""

IF PARAMETERS()<2
        lcreturn="Parameters not specified"
        llreturn=.f.
ELSE
        IF VARTYPE(lcsource)<>"C" OR VARTYPE(lccopy)<>"C"
                lcreturn="Parameters Invalid"
                llreturn=.f.
        ELSE
                IF !DIRECTORY(lcsource) OR !DIRECTORY(lccopy)
                        lcreturn="Directory Invalid"
                        llreturn=.f.            
                ENDIF
        ENDIF
ENDIF

IF llreturn
        SELECT 0
        CREATE CURSOR sync (ctype c(1),csource m(10),ccopy m(10),cAttribs
c(6))

        ?? " Examining differences..."
        m.Start=SECONDS()
        SET MESSAGE TO
        =proc_sync(lcsource,lccopy)
        ?? " took: ",ALLTRIM(STR(SECONDS()-m.Start,10,3)),"secs - "
        ?? " Updating..."
        m.Start=SECONDS()
        SELECT sync
        SCAN
                SCATTER MEMVAR memo
                IF "R"$cAttribs
                        ? "removing read-only: ",m.cCopy
                        SetFileAttribs(m.ccopy, "r")    && turn Off
Read-only
                ENDIF
                DO CASE
                        CASE ctype="C"
                                COPY FILE (m.csource) TO (m.ccopy)
                                IF FILE(m.ccopy)
                                        SET MESSAGE TO "Copied file:
"+m.ccopy
                                ELSE
                                        INSERT INTO SyncErr FROM MEMVAR
                                ENDIF
                        CASE ctype="D"
                                MD (m.ccopy)
                                IF DIRECTORY(m.ccopy)
                                        SET MESSAGE TO "Created directory:
"+m.ccopy
                                ELSE
                                        INSERT INTO SyncErr FROM MEMVAR
                                ENDIF
                        CASE ctype="U"
                                DELETE FILE (m.ccopy)
                                IF FILE(m.ccopy)
                                        INSERT INTO SyncErr FROM MEMVAR
                                ELSE
                                        COPY FILE (m.csource) TO (m.ccopy)
                                        IF FILE(m.ccopy)
                                                SET MESSAGE TO "Updated
file: "+m.ccopy
                                        ELSE
                                                INSERT INTO SyncErr FROM
MEMVAR
                                        ENDIF
                                ENDIF
                        CASE ctype="X"
                                DELETE FILE (m.ccopy)
                                IF FILE(m.ccopy)
                                        INSERT INTO SyncErr FROM MEMVAR
                                ELSE
                                        SET MESSAGE TO "Deleted file:
"+m.ccopy
                                ENDIF
                        CASE ctype="Z"
                                =AGRD (m.ccopy)
                                RD (m.ccopy)
                                IF DIRECTORY(m.ccopy)
                                        INSERT INTO SyncErr FROM MEMVAR
                                ELSE
                                        SET MESSAGE TO "Removed directory:
"+m.ccopy
                                ENDIF
                ENDCASE
        ENDSCAN
        ?? " took: ",ALLTRIM(STR(SECONDS()-m.Start,10,3)),"secs."
ENDIF

RETURN lcreturn

ENDPROC

*** 

PROCEDURE agrd
LPARAMETERS lcdir

LOCAL lchome,lndirs,lncounter
LOCAL ARRAY ladeldirs(1)

lchome=SYS(5)+CURDIR()

CD (lcdir)

SET SAFETY Off
DELETE FILE *.*
SET SAFETY on

lndirs=ADIR(ladeldirs,"","D",1)

IF lndirs>0
        FOR lncounter = 1 TO ALEN(ladeldirs,1)
                IF ladeldirs(lncounter,1)<>"." AND
ladeldirs(lncounter,1)<>".."
                        =agrd(lcdir+"\"+ladeldirs(lncounter,1))
                endif
        endfor
ENDIF

IF lndirs>0
        FOR lncounter = 1 TO ALEN(ladeldirs,1)
                IF ladeldirs(lncounter,1)<>"." AND
ladeldirs(lncounter,1)<>".."
                        RD (lcdir+"\"+ladeldirs(lncounter,1))
                endif
        endfor
ENDIF

CD (lchome)

RETURN

***

PROCEDURE proc_sync
LPARAMETERS lcsource,lccopy

LOCAL
llreturn,lnfiles,lndirs,lncopy,lncounter,lchome,lcaction,llcopies,lncopies,l
nresult,lnlocdirs
LOCAL array lafiles(1)
LOCAL array ladirs(1)
LOCAL ARRAY lacopies(1)
LOCAL ARRAY lalocdirs(1)
LOCAL ARRAY lacopy(1)

lcsource=ALLTRIM(lcsource)
lccopy=ALLTRIM(lccopy)
lchome=SYS(5)+CURDIR()
llcopies=.f.

IF DIRECTORY(lccopy)
        CD (lccopy)
        llcopies=.t.
        lncopies=ADIR(lacopies,"*.*","",1)
        lnlocdirs=ADIR(lalocdirs,"","D",1)
ENDIF

CD (lcsource)

lnfiles=ADIR(lafiles,"*.*","",1)
lndirs=ADIR(ladirs,"","D",1)

IF lnfiles>0
        FOR lncounter = 1 TO ALEN(lafiles,1)
                
                lcaction=""
                
                IF !FILE(lccopy+"\"+lafiles(lncounter,1))
                        lcaction="C"
                ELSE
                        lncopy=ADIR(lacopy,lccopy+"\"+lafiles(lncounter,1))
                        IF lncopy=1
                                DO case
                                        CASE
lafiles(lncounter,3)>lacopy(1,3)
                                                lcaction="U"
                                        CASE
lafiles(lncounter,3)=lacopy(1,3) AND lafiles(lncounter,4)>lacopy(1,4)
                                                lcaction="U"
                                ENDCASE
                        ENDIF
                ENDIF
                
                IF !EMPTY(lcaction)
                        INSERT INTO sync (ctype,csource,ccopy,cAttribs);
                        VALUES
(lcaction,ALLTRIM(lcsource)+"\"+ALLTRIM(lafiles(lncounter,1)),ALLTRIM(lccopy
)+"\"+ALLTRIM(lafiles(lncounter,1)),ALLTRIM(lafiles(lncounter,5)))
                ENDIF
                
        ENDFOR
ENDIF

IF lndirs>0
        FOR lncounter = 1 TO ALEN(ladirs,1)
                IF ladirs(lncounter,1)<>"." AND ladirs(lncounter,1)<>".."
                        
                        IF !DIRECTORY(lccopy+"\"+ladirs(lncounter,1))
                                INSERT INTO sync(ctype,csource,ccopy);
                                VALUES
("D","",ALLTRIM(lccopy)+"\"+ALLTRIM(ladirs(lncounter,1)))
                        ENDIF
        
=proc_sync(lcsource+"\"+ladirs(lncounter,1),lccopy+"\"+ladirs(lncounter,1))
                ENDIF
        ENDFOR
ENDIF

IF llcopies
IF lncopies>0 
        FOR lncounter = 1 TO ALEN(lacopies,1)
                
                lcaction=""
                lnresult=ASCAN(lafiles,lacopies(lncounter,1),-1,-1,1,1)
                IF lnresult=0
                        lcaction="X"                    
                ENDIF
                
                IF !EMPTY(lcaction)
                        INSERT INTO sync (ctype,csource,ccopy,cAttribs);
                        VALUES
(lcaction,"",ALLTRIM(lccopy)+"\"+ALLTRIM(lacopies(lncounter,1)),ALLTRIM(laco
pies(lncounter,5)))
                ENDIF
                                        
        ENDFOR
ENDIF
ENDIF

IF llcopies
IF lnlocdirs>0
        FOR lncounter = 1 TO ALEN(lalocdirs,1)
                lcaction=""
                lnresult=ASCAN(ladirs,lalocdirs(lncounter,1),-1,-1,1,1)
                IF lnresult=0
                        lcaction="Z"
                ENDIF
                
                IF !EMPTY(lcaction)
                        INSERT INTO sync (ctype,csource,ccopy);
                        VALUES
(lcaction,"",ALLTRIM(lccopy)+"\"+ALLTRIM(lalocdirs(lncounter,1)))
                ENDIF
                
        endfor
endif
endif

CD (lchome)

RETURN

PROCEDURE SetFileAttribs
LPARAMETERS pcFile, pcAttr

* Author: William GC Steinford 2003
* Takes a file and a list of attributes to change on the file, and does the
change
*
* pcFile  : either just the file name or the full path to the file.
*           Either way, the full path will be resolved using FULLPATH()
* pcAttrs : a list of attributes to change on the file
*           if the attribute character is Uppercase it will be turned on,
*             Lowercase, it will be turned off, 
*             Not listed, it will be left alone.
*           a,A - Archive
*           s,S - System
*           h,H - Hidden
*           r,R - Read Only
*           i,I - Not Content-Indexed
*           t,T - Temporary Storage (try to keep in memory)
*           N   - Normal (clear all other attributes)

*!*    BOOL SetFileAttributes(
*!*      LPCTSTR lpFileName,      // file name
*!*      DWORD dwFileAttributes   // attributes
*!*    )
*!*    DWORD GetFileAttributes(
*!*      LPCTSTR lpFileName   // name of file or directory
*!*    )

#define FILE_ATTRIBUTE_READONLY             0x00000001
#define FILE_ATTRIBUTE_HIDDEN               0x00000002
#define FILE_ATTRIBUTE_SYSTEM               0x00000004
#define FILE_ATTRIBUTE_DIRECTORY            0x00000010
#define FILE_ATTRIBUTE_ARCHIVE              0x00000020
#define FILE_ATTRIBUTE_ENCRYPTED            0x00000040
#define FILE_ATTRIBUTE_NORMAL               0x00000080
#define FILE_ATTRIBUTE_TEMPORARY            0x00000100
#define FILE_ATTRIBUTE_SPARSE_FILE          0x00000200
#define FILE_ATTRIBUTE_REPARSE_POINT        0x00000400
#define FILE_ATTRIBUTE_COMPRESSED           0x00000800
#define FILE_ATTRIBUTE_OFFLINE              0x00001000
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED  0x00002000

DECLARE INTEGER GetFileAttributes IN kernel32; 
    STRING lpFileName
DECLARE SHORT SetFileAttributes IN kernel32; 
    STRING lpFileName,; 
    INTEGER dwFileAttributes  

LOCAL lcFile, lnAttr, lcAttr, laDir[1]
lcFile = FULLPATH(pcFile)
* File() doesn't see Hidden or system files: if NOT FILE(pcFile)
IF adir(laDir,lcFile,'DHS')=0
  RETURN .F.
endif
lcAttr = upper(pcAttr)

if 'N' $ pcAttr
  * "NORMAL" must be used alone.
  lnRes = SetFileAttributes(lcFile,FILE_ATTRIBUTE_NORMAL)
  RETURN (lnRes<>0)
endif

lnAttr = GetFileAttributes( lcFile )
* These attributes Can't be set using SetFileAttributes:
lnAttr = BitAnd( lnAttr, BitNot( FILE_ATTRIBUTE_COMPRESSED ;
     + FILE_ATTRIBUTE_DIRECTORY + FILE_ATTRIBUTE_ENCRYPTED ;
     + FILE_ATTRIBUTE_REPARSE_POINT ;
     + FILE_ATTRIBUTE_SPARSE_FILE ) )
if 'A' $ lcAttr
  if 'A' $ pcAttr
    lnAttr = BitOr( lnAttr, FILE_ATTRIBUTE_ARCHIVE )
  else
    lnAttr = BitAnd( lnAttr, BitNot(FILE_ATTRIBUTE_ARCHIVE) )
  endif
endif
if 'R' $ lcAttr
  if 'R' $ pcAttr
    lnAttr = BitOr( lnAttr, FILE_ATTRIBUTE_READONLY )
  else
    lnAttr = BitAnd( lnAttr, BitNot(FILE_ATTRIBUTE_READONLY) )
  endif
endif
if 'H' $ lcAttr
  if 'H' $ pcAttr
    lnAttr = BitOr( lnAttr, FILE_ATTRIBUTE_HIDDEN )
  else
    lnAttr = BitAnd( lnAttr, BitNot(FILE_ATTRIBUTE_HIDDEN) )
  endif
endif
if 'S' $ lcAttr
  if 'S' $ pcAttr
    lnAttr = BitOr( lnAttr, FILE_ATTRIBUTE_SYSTEM )
  else
    lnAttr = BitAnd( lnAttr, BitNot(FILE_ATTRIBUTE_SYSTEM) )
  endif
endif
if 'I' $ lcAttr
  if 'I' $ pcAttr
    lnAttr = BitOr( lnAttr, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED )
  else
    lnAttr = BitAnd( lnAttr, BitNot(FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) )
  endif
endif
if 'T' $ lcAttr
  if 'S' $ pcAttr
    lnAttr = BitOr( lnAttr, FILE_ATTRIBUTE_TEMPORARY )
  else
    lnAttr = BitAnd( lnAttr, BitNot(FILE_ATTRIBUTE_TEMPORARY) )
  endif
endif
if 'N' $ lcAttr
  lnAttr = iif('N'$pcAttr, FILE_ATTRIBUTE_NORMAL, lnAttr )
endif

lnRes = SetFileAttributes(lcFile,lnAttr)
RETURN (lnRes<>0)

FUNCTION GetFileAttrib( tcFName )
*GetFileAttrib( cFName ) Return the File Attributes (RSHA)
*!*    DWORD GetFileAttributes(
*!*      LPCTSTR lpFileName   // name of file or directory
*!*    )
  DECLARE LONG GetFileAttributes IN Win32Api AS util_GetFileAttributes ;
    STRING LPCTSTR_lpFileName 
  LOCAL lnAttr, lcAttr
  lnAttr = util_GetFileAttributes( tcFName )
  CLEAR DLLS util_GetFileAttributes
  if lnAttr=0xFFFF
    RETURN 'error'
  ENDIF
  lcAttr = iif( BITAND(lnAttr,util_FILE_ATTRIBUTE_READONLY )>0, 'R', '' ) ;
         + iif( BITAND(lnAttr,util_FILE_ATTRIBUTE_HIDDEN   )>0, 'H', '' ) ;
         + iif( BITAND(lnAttr,util_FILE_ATTRIBUTE_SYSTEM   )>0, 'S', '' ) ;
         + iif( BITAND(lnAttr,util_FILE_ATTRIBUTE_ARCHIVE  )>0, 'A', '' ) ;
         + iif( BITAND(lnAttr,util_FILE_ATTRIBUTE_DIRECTORY)>0, 'D', '' )
  RETURN lcAttr
ENDFUNC

************************ end ******************************



_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/profox
OT-free version of this list: http://leafe.com/mailman/listinfo/profoxtech
** All postings, unless explicitly stated otherwise, are the opinions of the 
author, and do not constitute legal or medical advice. This statement is added 
to the messages for those lawyers who are too stupid to see the obvious.

Reply via email to