@@ -11,6 +11,8 @@ const DavStatus_1 = require("ithit.webdav.server/DavStatus");
1111const path_1 = require ( "path" ) ;
1212const DateLockInfo_1 = require ( "./DateLockInfo" ) ;
1313const FileSystemInfoExtension_1 = require ( "./ExtendedAttributes/FileSystemInfoExtension" ) ;
14+ const util_1 = require ( "util" ) ;
15+ const child_process_1 = require ( "child_process" ) ;
1416/**
1517 * Base class for WebDAV items (folders, files, etc).
1618 */
@@ -21,6 +23,10 @@ class DavHierarchyItem {
2123 * @param path Encoded path relative to WebDAV root folder.
2224 */
2325 constructor ( directory , context , path , stats ) {
26+ /**
27+ * Name of properties attribute.
28+ */
29+ this . propertiesAttributeName = "Properties" ;
2430 /**
2531 * Name of locks attribute.
2632 */
@@ -87,10 +93,10 @@ class DavHierarchyItem {
8793 * @param allprop Whether all properties shall be retrieved.
8894 * @returns Property values.
8995 */
90- getProperties ( props , allprop ) {
91- let propertyValues = this . getPropertyValues ( ) ;
96+ async getProperties ( props , allprop ) {
97+ let propertyValues = await this . getPropertyValues ( ) ;
9298 if ( ! allprop ) {
93- propertyValues = propertyValues . filter ( item => item . qualifiedName ) ;
99+ propertyValues = propertyValues . filter ( item => props . findIndex ( p => p . name === item . qualifiedName . name ) > - 1 ) ;
94100 }
95101 return propertyValues ;
96102 }
@@ -100,8 +106,8 @@ class DavHierarchyItem {
100106 * Retrieves names of all user defined properties.
101107 * @returns Property names.
102108 */
103- getPropertyNames ( ) {
104- const propertyValues = this . getPropertyValues ( ) ;
109+ async getPropertyNames ( ) {
110+ const propertyValues = await this . getPropertyValues ( ) ;
105111 const g = propertyValues . map ( item => item . qualifiedName ) ;
106112 return g ;
107113 }
@@ -113,7 +119,54 @@ class DavHierarchyItem {
113119 * @param delProps Properties to be deleted.
114120 * @param multistatus Information about properties that failed to create, update or delate.
115121 */
116- updateProperties ( setProps , delProps , multistatus ) { }
122+ async updateProperties ( setProps , delProps , multistatus ) {
123+ await this . requireHasToken ( ) ;
124+ let propertyValues = await this . getPropertyValues ( ) ;
125+ for ( const propToSet of setProps ) {
126+ // Microsoft Mini-redirector may update file creation date, modification date and access time passing properties:
127+ // <Win32CreationTime xmlns="urn:schemas-microsoft-com:">Thu, 28 Mar 2013 20:15:34 GMT</Win32CreationTime>
128+ // <Win32LastModifiedTime xmlns="urn:schemas-microsoft-com:">Thu, 28 Mar 2013 20:36:24 GMT</Win32LastModifiedTime>
129+ // <Win32LastAccessTime xmlns="urn:schemas-microsoft-com:">Thu, 28 Mar 2013 20:36:24 GMT</Win32LastAccessTime>
130+ // In this case update creation and modified date in your storage or do not save this properties at all, otherwise
131+ // Windows Explorer will display creation and modification date from this props and it will differ from the values
132+ // in the Created and Modified fields in your storage
133+ if ( propToSet . qualifiedName . namespace == "urn:schemas-microsoft-com:" ) {
134+ const creationTimeUtc = new Date ( ) ;
135+ creationTimeUtc . setTime ( Date . parse ( propToSet . value ) ) ;
136+ switch ( propToSet . qualifiedName . name ) {
137+ case "Win32CreationTime" : {
138+ const { stderr } = await util_1 . promisify ( child_process_1 . exec ) ( `powershell $(Get-Item ${ this . directory } ).creationtime=$(Get-Date "${ creationTimeUtc . toISOString ( ) } ")` ) ;
139+ if ( stderr ) {
140+ throw stderr ;
141+ }
142+ break ;
143+ }
144+ case "Win32LastModifiedTime" : {
145+ const { stderr } = await util_1 . promisify ( child_process_1 . exec ) ( `powershell $(Get-Item ${ this . directory } ).lastwritetime=$(Get-Date "${ creationTimeUtc . toISOString ( ) } ")` ) ;
146+ if ( stderr ) {
147+ throw stderr ;
148+ }
149+ break ;
150+ }
151+ default :
152+ this . context . logger . logDebug ( `Unspecified case:
153+ DavHierarchyItem.UpdateProperties ${ propToSet . qualifiedName . name } from ${ propToSet . qualifiedName . namespace } namesapce` ) ;
154+ break ;
155+ }
156+ }
157+ else {
158+ const existingProp = propertyValues . filter ( p => p . qualifiedName . name === propToSet . qualifiedName . name ) [ 0 ] || null ;
159+ if ( existingProp != null ) {
160+ existingProp . value = propToSet . value ;
161+ }
162+ else {
163+ propertyValues . push ( propToSet ) ;
164+ }
165+ }
166+ }
167+ propertyValues = propertyValues . filter ( prop => ! ( delProps . length && delProps . findIndex ( delProp => delProp . name === prop . qualifiedName . name ) > - 1 ) ) ;
168+ await FileSystemInfoExtension_1 . FileSystemInfoExtension . setExtendedAttribute ( this . directory , this . propertiesAttributeName , propertyValues ) ;
169+ }
117170 //$>
118171 //$<IMsItem.GetFileAttributes
119172 /**
@@ -233,16 +286,26 @@ class DavHierarchyItem {
233286 /**
234287 * Check that if the item is locked then client has submitted correct lock token.
235288 */
236- requireHasToken ( skipShared = false ) {
289+ async requireHasToken ( skipShared = false ) {
290+ const locks = await this . getLocks ( ) ;
291+ if ( locks !== null && locks . length ) {
292+ const clientLockTokens = this . context . request . clientLockTokens ;
293+ const resultFiltering = locks . filter ( l => ! ( clientLockTokens . length && clientLockTokens . findIndex ( clientLockToken => clientLockToken === l . lockToken ) > - 1 ) ) ;
294+ if ( resultFiltering . length ) {
295+ throw new LockedException_1 . LockedException ( ) ;
296+ }
297+ }
237298 return Promise . resolve ( ) ;
238299 }
239300 /**
240301 * Retrieves list of user defined propeties for this item.
241302 * @returns List of user defined properties.
242303 */
243- getPropertyValues ( ) {
244- if ( this . propertyValues === null ) {
304+ async getPropertyValues ( ) {
305+ if ( this . propertyValues === null || this . propertyValues === undefined ) {
245306 this . propertyValues = new Array ( ) ;
307+ this . propertyValues = await FileSystemInfoExtension_1 . FileSystemInfoExtension . getExtendedAttribute ( this . directory , this . propertiesAttributeName ) ;
308+ this . propertyValues = Array . isArray ( this . propertyValues ) ? this . propertyValues . filter ( item => Object . keys ( item ) . length && item . constructor === Object ) : [ ] ;
246309 }
247310 return this . propertyValues ;
248311 }
@@ -272,8 +335,8 @@ class DavHierarchyItem {
272335 async saveLock ( lockInfo ) {
273336 let locks = await this . getLocks ( true ) ;
274337 // remove all expired locks
275- locks = locks . filter ( x => x . expiration <= Date . now ( ) ) ;
276- const existingLock = locks . filter ( x => x . lockToken < = lockInfo . lockToken ) [ 0 ] || null ;
338+ locks = locks . filter ( x => Date . now ( ) <= x . expiration ) ;
339+ const existingLock = locks . filter ( x => x . lockToken == = lockInfo . lockToken ) [ 0 ] || null ;
277340 if ( existingLock ) {
278341 existingLock . timeOut = lockInfo . timeOut ;
279342 existingLock . level = lockInfo . level ;
0 commit comments