Skip to content

Commit e5637dc

Browse files
committed
1.1.187-Beta
1 parent 75c8166 commit e5637dc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+394
-199
lines changed
12.3 KB
Binary file not shown.

FileSystem/App_Data/Storage/Notes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
My notes file text

FileSystem/App_Data/Storage/Stat.xlsx

8.51 KB
Binary file not shown.

FileSystem/DavContext.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const path_1 = require("path");
55
const DavFile_1 = require("./DavFile");
66
const DavFolder_1 = require("./DavFolder");
77
/**
8-
* Implementation of {@link DavContext}.
8+
* Implementation of {@link DavContextBase}.
99
* Resolves hierarchy items by paths.
1010
*/
1111
class DavContext extends DavContextBase_1.DavContextBase {
@@ -22,14 +22,23 @@ class DavContext extends DavContextBase_1.DavContextBase {
2222
* @param prefixes Http listener prefixes.
2323
* @param repositoryPath Local path to repository.
2424
*/
25-
constructor(listenerContext, prefixes, principal, repositoryPath, logger) {
25+
constructor(listenerContext, prefixes, principal, repositoryPath, logger, socketService) {
2626
super(listenerContext, prefixes);
2727
this.logger = logger;
2828
this.repositoryPath = repositoryPath;
29+
this.socketService = socketService;
2930
if (principal !== null) {
3031
this.identity = principal;
3132
}
3233
}
34+
/**
35+
* Can trim any character or set of characters from the ends of a string.
36+
* Uses a Regex escapement to replace them with empty.
37+
* @param source
38+
* @param chars A string or array of characters desired to be trimmed.
39+
* @param ignoreCase
40+
* @returns {string}
41+
*/
3342
trim(source, chars, ignoreCase) {
3443
if (chars === '') {
3544
return source;
@@ -66,14 +75,5 @@ class DavContext extends DavContextBase_1.DavContextBase {
6675
return null;
6776
// no hierarchy item that corresponds to path parameter was found in the repository
6877
}
69-
//$>
70-
/**
71-
* Returns the physical file path that corresponds to the specified virtual path on the Web server.
72-
* @param relativePath Path relative to WebDAV root folder.
73-
* @returns Corresponding path in file system.
74-
*/
75-
mapPath(relativePath) {
76-
return this.repositoryPath;
77-
}
7878
}
7979
exports.DavContext = DavContext;

FileSystem/DavContext.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import { ILogger } from "ithit.webdav.server/ILogger";
66
import { sep } from "path";
77
import { DavFile } from "./DavFile";
88
import { DavFolder } from "./DavFolder";
9+
import { WebSocketsService } from "./WebSocketsService";
910

1011
/**
11-
* Implementation of {@link DavContext}.
12+
* Implementation of {@link DavContextBase}.
1213
* Resolves hierarchy items by paths.
1314
*/
1415
export class DavContext extends DavContextBase {
@@ -18,6 +19,8 @@ export class DavContext extends DavContextBase {
1819
*/
1920
public repositoryPath: string;
2021

22+
public socketService: WebSocketsService;
23+
2124
/**
2225
* Gets WebDAV Logger instance.
2326
*/
@@ -44,17 +47,26 @@ export class DavContext extends DavContextBase {
4447
* @param prefixes Http listener prefixes.
4548
* @param repositoryPath Local path to repository.
4649
*/
47-
constructor(listenerContext: DavRequest, prefixes: DavResponse, principal: any, repositoryPath: string, logger: ILogger) {
50+
constructor(listenerContext: DavRequest, prefixes: DavResponse, principal: any, repositoryPath: string, logger: ILogger, socketService: WebSocketsService) {
4851
super(listenerContext, prefixes);
4952
this.logger = logger;
5053
this.repositoryPath = repositoryPath;
54+
this.socketService = socketService;
5155
if (principal !== null) {
5256
this.identity = principal;
5357
}
5458

5559
}
5660

57-
public trim(source: string, chars?: string | string[], ignoreCase?: boolean): string {
61+
/**
62+
* Can trim any character or set of characters from the ends of a string.
63+
* Uses a Regex escapement to replace them with empty.
64+
* @param source
65+
* @param chars A string or array of characters desired to be trimmed.
66+
* @param ignoreCase
67+
* @returns {string}
68+
*/
69+
private trim(source: string, chars?: string | string[], ignoreCase?: boolean): string {
5870
if (chars === '') {
5971
return source;
6072
}
@@ -95,14 +107,4 @@ export class DavContext extends DavContextBase {
95107
// no hierarchy item that corresponds to path parameter was found in the repository
96108
}
97109
//$>
98-
99-
/**
100-
* Returns the physical file path that corresponds to the specified virtual path on the Web server.
101-
* @param relativePath Path relative to WebDAV root folder.
102-
* @returns Corresponding path in file system.
103-
*/
104-
public mapPath(relativePath: string): string {
105-
106-
return this.repositoryPath;
107-
}
108110
}

FileSystem/DavFile.js

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
1919
* Gets content type.
2020
*/
2121
get contentType() {
22-
let conType = String(mime_types_1.lookup(this.directory));
22+
let conType = String(mime_types_1.lookup(this.fullPath));
2323
if (!conType) {
2424
conType = `application/octet-stream`;
2525
}
@@ -65,7 +65,7 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
6565
* @returns File instance or null if physical file is not found in file system.
6666
*/
6767
static async getFile(context, path) {
68-
const filePath = EncodeUtil_1.EncodeUtil.decodeUrlPart(context.mapPath(path) + path_1.sep + path);
68+
const filePath = EncodeUtil_1.EncodeUtil.decodeUrlPart(context.repositoryPath + path_1.sep + path);
6969
try {
7070
await util_1.promisify(fs_1.access)(filePath, constants_1.F_OK);
7171
}
@@ -78,8 +78,8 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
7878
return null;
7979
}
8080
const davFile = new DavFile(filePath, context, path, file);
81-
davFile.serialNumber = Number(await FileSystemInfoExtension_1.FileSystemInfoExtension.getExtendedAttribute(davFile.directory, "SerialNumber"));
82-
davFile.totalContentLength = Number(await FileSystemInfoExtension_1.FileSystemInfoExtension.getExtendedAttribute(davFile.directory, "TotalContentLength"));
81+
davFile.serialNumber = Number(await FileSystemInfoExtension_1.FileSystemInfoExtension.getExtendedAttribute(davFile.fullPath, "SerialNumber"));
82+
davFile.totalContentLength = Number(await FileSystemInfoExtension_1.FileSystemInfoExtension.getExtendedAttribute(davFile.fullPath, "TotalContentLength"));
8383
return davFile;
8484
}
8585
/**
@@ -103,8 +103,8 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
103103
if (this.containsDownloadParam(this.context.request.rawUrl)) {
104104
this.addContentDisposition(this.name);
105105
}
106-
const fd = await util_1.promisify(fs_1.open)(this.directory, 'r');
107-
const fileStream = fs_1.createReadStream(this.directory, {
106+
const fd = await util_1.promisify(fs_1.open)(this.fullPath, 'r');
107+
const fileStream = fs_1.createReadStream(this.fullPath, {
108108
flags: 'r',
109109
fd: fd,
110110
start: startIndex,
@@ -159,16 +159,26 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
159159
if (this.fileInfo.size < startIndex) {
160160
throw new DavException_1.DavException("Previous piece of file was not uploaded.", undefined, DavStatus_1.DavStatus.PRECONDITION_FAILED);
161161
}
162-
await FileSystemInfoExtension_1.FileSystemInfoExtension.setExtendedAttribute(this.directory, "TotalContentLength", Number(totalFileSize));
163-
await FileSystemInfoExtension_1.FileSystemInfoExtension.setExtendedAttribute(this.directory, "SerialNumber", (this.serialNumber || 0) + 1);
164-
const fd = await util_1.promisify(fs_1.open)(this.directory, 'r+');
165-
await util_1.promisify(fs_1.ftruncate)(fd, 0);
166-
const fileStream = fs_1.createWriteStream(this.directory, {
162+
await FileSystemInfoExtension_1.FileSystemInfoExtension.setExtendedAttribute(this.fullPath, "TotalContentLength", Number(totalFileSize));
163+
await FileSystemInfoExtension_1.FileSystemInfoExtension.setExtendedAttribute(this.fullPath, "SerialNumber", (this.serialNumber || 0) + 1);
164+
const fd = await util_1.promisify(fs_1.open)(this.fullPath, 'r+');
165+
if (startIndex == 0 && this.fileInfo.size > 0) {
166+
await util_1.promisify(fs_1.ftruncate)(fd, 0);
167+
}
168+
const fileStream = fs_1.createWriteStream(this.fullPath, {
167169
flags: 'r+',
168-
fd
170+
fd,
171+
start: startIndex
172+
});
173+
await new Promise((resolve, reject) => {
174+
fileStream.on('error', (error) => reject(error));
175+
content.on('close', () => fileStream.end());
176+
content.on('finish', () => resolve());
177+
content.on('end', () => resolve());
178+
content.on('error', (error) => reject(error));
179+
content.pipe(fileStream);
180+
content.resume();
169181
});
170-
content.pipe(fileStream);
171-
content.resume();
172182
return true;
173183
}
174184
//$>
@@ -182,10 +192,10 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
182192
*/
183193
async copyTo(destFolder, destName, deep, multistatus) {
184194
const targetFolder = destFolder;
185-
if (targetFolder == null || !await util_1.promisify(fs_1.exists)(targetFolder.directory)) {
195+
if (targetFolder == null || !await util_1.promisify(fs_1.exists)(targetFolder.fullPath)) {
186196
throw new DavException_1.DavException("Target directory doesn't exist", undefined, DavStatus_1.DavStatus.CONFLICT);
187197
}
188-
const newFilePath = path_1.join(targetFolder.directory, destName);
198+
const newFilePath = path_1.join(targetFolder.fullPath, destName);
189199
const targetPath = (targetFolder.path + EncodeUtil_1.EncodeUtil.encodeUrlPart(destName));
190200
// If an item with the same name exists - remove it.
191201
try {
@@ -201,7 +211,8 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
201211
}
202212
// Copy the file togather with all extended attributes (custom props and locks).
203213
try {
204-
await util_1.promisify(fs_1.copyFile)(this.directory, newFilePath);
214+
await util_1.promisify(fs_1.copyFile)(this.fullPath, newFilePath);
215+
this.context.socketService.notifyRefresh(targetFolder.path.replace(/\\/g, '/').replace(/\/$/, ""));
205216
}
206217
catch (err) {
207218
/*if(err.errno && err.errno === EACCES) {
@@ -225,10 +236,10 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
225236
async moveTo(destFolder, destName, multistatus) {
226237
await this.requireHasToken();
227238
const targetFolder = destFolder;
228-
if (targetFolder == null || !await util_1.promisify(fs_1.exists)(targetFolder.directory)) {
239+
if (targetFolder == null || !await util_1.promisify(fs_1.exists)(targetFolder.fullPath)) {
229240
throw new DavException_1.DavException("Target directory doesn't exist", undefined, DavStatus_1.DavStatus.CONFLICT);
230241
}
231-
const newDirPath = path_1.join(targetFolder.directory, destName);
242+
const newDirPath = path_1.join(targetFolder.fullPath, destName);
232243
const targetPath = (targetFolder.path + EncodeUtil_1.EncodeUtil.encodeUrlPart(destName));
233244
// If an item with the same name exists in target directory - remove it.
234245
try {
@@ -243,18 +254,22 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
243254
return;
244255
}
245256
// Move the file.
246-
await util_1.promisify(fs_1.rename)(this.directory, newDirPath);
257+
await util_1.promisify(fs_1.rename)(this.fullPath, newDirPath);
247258
// Locks should not be copied, delete them.
248259
await FileSystemInfoExtension_1.FileSystemInfoExtension.setExtendedAttribute(newDirPath, "Locks", {});
260+
this.context.socketService.notifyRefresh(targetFolder.path.replace(/\\/g, '/').replace(/\/$/, ""));
261+
this.context.socketService.notifyRefresh(this.getParentPath(this.path));
249262
}
250263
//$>
251264
//$<IHierarchyItem.Delete
252265
/**
253266
* Called whan this file is being deleted.
254267
* @param multistatus Information about items that failed to delete.
255268
*/
256-
delete(multistatus) {
257-
return util_1.promisify(fs_1.unlink)(this.directory);
269+
async delete(multistatus) {
270+
await util_1.promisify(fs_1.unlink)(this.fullPath);
271+
this.context.socketService.notifyRefresh(this.getParentPath(this.path));
272+
return;
258273
}
259274
//$>
260275
//$<IResumableUpload.CancelUpload

FileSystem/DavFile.ts

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export class DavFile extends DavHierarchyItem implements IFile, IResumableUpload
2828
* Gets content type.
2929
*/
3030
get contentType(): string {
31-
let conType = String(lookup(this.directory));
31+
let conType = String(lookup(this.fullPath));
3232
if (!conType) {
3333
conType = `application/octet-stream`;
3434
}
@@ -103,7 +103,7 @@ export class DavFile extends DavHierarchyItem implements IFile, IResumableUpload
103103
* @returns File instance or null if physical file is not found in file system.
104104
*/
105105
public static async getFile(context: DavContext, path: string): Promise<DavFile | null> {
106-
const filePath = EncodeUtil.decodeUrlPart(context.mapPath(path) + sep + path);
106+
const filePath = EncodeUtil.decodeUrlPart(context.repositoryPath + sep + path);
107107
try {
108108
await promisify(access)(filePath, F_OK);
109109
} catch(err) {
@@ -118,9 +118,9 @@ export class DavFile extends DavHierarchyItem implements IFile, IResumableUpload
118118

119119
const davFile: DavFile = new DavFile(filePath, context, path, file);
120120

121-
davFile.serialNumber = Number(await FileSystemInfoExtension.getExtendedAttribute<number>(davFile.directory, "SerialNumber"));
121+
davFile.serialNumber = Number(await FileSystemInfoExtension.getExtendedAttribute<number>(davFile.fullPath, "SerialNumber"));
122122
davFile.totalContentLength = Number(await FileSystemInfoExtension.getExtendedAttribute<number>(
123-
davFile.directory,
123+
davFile.fullPath,
124124
"TotalContentLength"
125125
));
126126

@@ -150,8 +150,8 @@ export class DavFile extends DavHierarchyItem implements IFile, IResumableUpload
150150
this.addContentDisposition(this.name);
151151
}
152152

153-
const fd = await promisify(open)(this.directory, 'r');
154-
const fileStream = createReadStream(this.directory, {
153+
const fd = await promisify(open)(this.fullPath, 'r');
154+
const fileStream = createReadStream(this.fullPath, {
155155
flags: 'r',
156156
fd: fd,
157157
start: startIndex,
@@ -212,16 +212,28 @@ export class DavFile extends DavHierarchyItem implements IFile, IResumableUpload
212212
throw new DavException("Previous piece of file was not uploaded.", undefined, DavStatus.PRECONDITION_FAILED);
213213
}
214214

215-
await FileSystemInfoExtension.setExtendedAttribute(this.directory, "TotalContentLength", Number(totalFileSize));
216-
await FileSystemInfoExtension.setExtendedAttribute(this.directory, "SerialNumber", (this.serialNumber || 0) + 1);
217-
const fd = await promisify(open)(this.directory, 'r+');
218-
await promisify(ftruncate)(fd, 0);
219-
const fileStream = createWriteStream(this.directory, {
215+
await FileSystemInfoExtension.setExtendedAttribute(this.fullPath, "TotalContentLength", Number(totalFileSize));
216+
await FileSystemInfoExtension.setExtendedAttribute(this.fullPath, "SerialNumber", (this.serialNumber || 0) + 1);
217+
const fd = await promisify(open)(this.fullPath, 'r+');
218+
if (startIndex == 0 && this.fileInfo.size > 0) {
219+
await promisify(ftruncate)(fd, 0);
220+
}
221+
222+
const fileStream = createWriteStream(this.fullPath, {
220223
flags: 'r+',
221-
fd
224+
fd,
225+
start: startIndex
226+
});
227+
228+
await new Promise((resolve, reject) => {
229+
fileStream.on('error', (error) => reject(error));
230+
content.on('close', () => fileStream.end());
231+
content.on('finish', () => resolve());
232+
content.on('end', () => resolve());
233+
content.on('error', (error) => reject(error));
234+
content.pipe(fileStream);
235+
content.resume();
222236
});
223-
content.pipe(fileStream);
224-
content.resume();
225237

226238
return true;
227239
}
@@ -237,11 +249,11 @@ export class DavFile extends DavHierarchyItem implements IFile, IResumableUpload
237249
*/
238250
public async copyTo(destFolder: IItemCollection, destName: string, deep: boolean, multistatus: MultistatusException): Promise<void> {
239251
const targetFolder = destFolder as DavFolder;
240-
if (targetFolder == null || !await promisify(exists)(targetFolder.directory)) {
252+
if (targetFolder == null || !await promisify(exists)(targetFolder.fullPath)) {
241253
throw new DavException("Target directory doesn't exist", undefined, DavStatus.CONFLICT);
242254
}
243255

244-
const newFilePath = join(targetFolder.directory, destName);
256+
const newFilePath = join(targetFolder.fullPath, destName);
245257
const targetPath = (targetFolder.path + EncodeUtil.encodeUrlPart(destName));
246258
// If an item with the same name exists - remove it.
247259
try {
@@ -260,7 +272,8 @@ export class DavFile extends DavHierarchyItem implements IFile, IResumableUpload
260272

261273
// Copy the file togather with all extended attributes (custom props and locks).
262274
try {
263-
await promisify(copyFile)(this.directory, newFilePath);
275+
await promisify(copyFile)(this.fullPath, newFilePath);
276+
this.context.socketService.notifyRefresh(targetFolder.path.replace(/\\/g, '/').replace(/\/$/, ""));
264277
} catch (err) {
265278
/*if(err.errno && err.errno === EACCES) {
266279
const ex = new NeedPrivilegesException("Not enough privileges");
@@ -285,11 +298,11 @@ export class DavFile extends DavHierarchyItem implements IFile, IResumableUpload
285298
public async moveTo(destFolder: IItemCollection, destName: string, multistatus: MultistatusException): Promise<void> {
286299
await this.requireHasToken();
287300
const targetFolder = destFolder as DavFolder;
288-
if (targetFolder == null || !await promisify(exists)(targetFolder.directory)) {
301+
if (targetFolder == null || !await promisify(exists)(targetFolder.fullPath)) {
289302
throw new DavException("Target directory doesn't exist", undefined, DavStatus.CONFLICT);
290303
}
291304

292-
const newDirPath = join(targetFolder.directory, destName);
305+
const newDirPath = join(targetFolder.fullPath, destName);
293306
const targetPath = (targetFolder.path + EncodeUtil.encodeUrlPart(destName));
294307

295308
// If an item with the same name exists in target directory - remove it.
@@ -307,10 +320,13 @@ export class DavFile extends DavHierarchyItem implements IFile, IResumableUpload
307320
}
308321

309322
// Move the file.
310-
await promisify(rename)(this.directory, newDirPath);
323+
await promisify(rename)(this.fullPath, newDirPath);
311324

312325
// Locks should not be copied, delete them.
313326
await FileSystemInfoExtension.setExtendedAttribute(newDirPath, "Locks", {});
327+
328+
this.context.socketService.notifyRefresh(targetFolder.path.replace(/\\/g, '/').replace(/\/$/, ""));
329+
this.context.socketService.notifyRefresh(this.getParentPath(this.path));
314330
}
315331
//$>
316332

@@ -319,8 +335,11 @@ export class DavFile extends DavHierarchyItem implements IFile, IResumableUpload
319335
* Called whan this file is being deleted.
320336
* @param multistatus Information about items that failed to delete.
321337
*/
322-
public delete(multistatus: MultistatusException): Promise<void> {
323-
return promisify(unlink)(this.directory);
338+
public async delete(multistatus: MultistatusException): Promise<void> {
339+
await promisify(unlink)(this.fullPath);
340+
this.context.socketService.notifyRefresh(this.getParentPath(this.path));
341+
342+
return;
324343
}
325344
//$>
326345

0 commit comments

Comments
 (0)