Skip to content

Commit f8475b7

Browse files
committed
1.0.67-alpha
1 parent 548af32 commit f8475b7

File tree

13 files changed

+212
-49
lines changed

13 files changed

+212
-49
lines changed

FileSystem/DavContext.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class DavContext extends DavContextBase_1.DavContextBase {
4242
}
4343
return source.replace(/^\s+|\s+$/g, '');
4444
}
45+
//$<DavContextBase.GetHierarchyItem
4546
/**
4647
* Creates {@link IHierarchyItem} instance by path.
4748
* @param path Item relative path including query string.
@@ -65,6 +66,7 @@ class DavContext extends DavContextBase_1.DavContextBase {
6566
return null;
6667
// no hierarchy item that corresponds to path parameter was found in the repository
6768
}
69+
//$>
6870
/**
6971
* Returns the physical file path that corresponds to the specified virtual path on the Web server.
7072
* @param relativePath Path relative to WebDAV root folder.

FileSystem/DavFile.js

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ 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 = context.mapPath(path) + path_1.sep + path;
69-
const existFile = await util_1.promisify(fs_1.exists)(filePath);
70-
if (!existFile) {
68+
const filePath = EncodeUtil_1.EncodeUtil.decodeUrlPart(context.mapPath(path) + path_1.sep + path);
69+
try {
70+
await util_1.promisify(fs_1.access)(filePath, constants_1.F_OK);
71+
}
72+
catch (err) {
7173
return null;
7274
}
7375
const file = await util_1.promisify(fs_1.stat)(filePath);
@@ -199,7 +201,7 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
199201
}
200202
// Copy the file togather with all extended attributes (custom props and locks).
201203
try {
202-
await util_1.promisify(fs_1.copyFile)(this.directory, newFilePath, constants_1.COPYFILE_EXCL);
204+
await util_1.promisify(fs_1.copyFile)(this.directory, newFilePath);
203205
}
204206
catch (err) {
205207
/*if(err.errno && err.errno === EACCES) {
@@ -220,7 +222,28 @@ class DavFile extends DavHierarchyItem_1.DavHierarchyItem {
220222
* @param destName New name of this file.
221223
* @param multistatus Information about items that failed to move.
222224
*/
223-
moveTo(destFolder, destName, multistatus) {
225+
async moveTo(destFolder, destName, multistatus) {
226+
await this.requireHasToken();
227+
const targetFolder = destFolder;
228+
if (targetFolder == null || !await util_1.promisify(fs_1.exists)(targetFolder.directory)) {
229+
throw new DavException_1.DavException("Target directory doesn't exist", undefined, DavStatus_1.DavStatus.CONFLICT);
230+
}
231+
const newDirPath = path_1.join(targetFolder.directory, destName);
232+
const targetPath = (targetFolder.path + EncodeUtil_1.EncodeUtil.encodeUrlPart(destName));
233+
// If an item with the same name exists in target directory - remove it.
234+
try {
235+
const item = await this.context.getHierarchyItem(targetPath);
236+
if (item != null) {
237+
await item.delete(multistatus);
238+
}
239+
}
240+
catch (err) {
241+
// Report exception to client and continue with other items by returning from recursion.
242+
multistatus.addInnerException(targetPath, undefined, err);
243+
return;
244+
}
245+
// Move the file.
246+
await util_1.promisify(fs_1.rename)(this.directory, newDirPath);
224247
}
225248
//$>
226249
//$<IHierarchyItem.Delete

FileSystem/DavFile.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createWriteStream, exists, ftruncate, open, stat, Stats, createReadStream, copyFile, unlink } from "fs";
1+
import { createWriteStream, exists, ftruncate, open, stat, Stats, createReadStream, copyFile, unlink, rename, access } from "fs";
22
import { IncomingMessage, ServerResponse } from "http";
33
import { IFile } from "ithit.webdav.server/Class1/IFile";
44
import { DavException } from "ithit.webdav.server/DavException";
@@ -13,7 +13,7 @@ import { DavContext } from "./DavContext";
1313
import { DavHierarchyItem } from "./DavHierarchyItem";
1414
import { FileSystemInfoExtension } from "./ExtendedAttributes/FileSystemInfoExtension";
1515
import { DavFolder } from "./DavFolder";
16-
import { COPYFILE_EXCL } from "constants";
16+
import { F_OK } from "constants";
1717

1818
/**
1919
* Represents file in WebDAV repository.
@@ -101,9 +101,10 @@ export class DavFile extends DavHierarchyItem implements IFile {
101101
* @returns File instance or null if physical file is not found in file system.
102102
*/
103103
public static async getFile(context: DavContext, path: string): Promise<DavFile | null> {
104-
const filePath: string = context.mapPath(path) + sep + path;
105-
const existFile = await promisify(exists)(filePath);
106-
if (!existFile) {
104+
const filePath = EncodeUtil.decodeUrlPart(context.mapPath(path) + sep + path);
105+
try {
106+
await promisify(access)(filePath, F_OK);
107+
} catch(err) {
107108
return null;
108109
}
109110

@@ -257,7 +258,7 @@ export class DavFile extends DavHierarchyItem implements IFile {
257258

258259
// Copy the file togather with all extended attributes (custom props and locks).
259260
try {
260-
await promisify(copyFile)(this.directory, newFilePath, COPYFILE_EXCL);
261+
await promisify(copyFile)(this.directory, newFilePath);
261262
} catch (err) {
262263
/*if(err.errno && err.errno === EACCES) {
263264
const ex = new NeedPrivilegesException("Not enough privileges");
@@ -279,7 +280,32 @@ export class DavFile extends DavHierarchyItem implements IFile {
279280
* @param destName New name of this file.
280281
* @param multistatus Information about items that failed to move.
281282
*/
282-
public moveTo(destFolder: IItemCollection, destName: string, multistatus: MultistatusException): void {
283+
public async moveTo(destFolder: IItemCollection, destName: string, multistatus: MultistatusException): Promise<void> {
284+
await this.requireHasToken();
285+
const targetFolder = destFolder as DavFolder;
286+
if (targetFolder == null || !await promisify(exists)(targetFolder.directory)) {
287+
throw new DavException("Target directory doesn't exist", undefined, DavStatus.CONFLICT);
288+
}
289+
290+
const newDirPath = join(targetFolder.directory, destName);
291+
const targetPath = (targetFolder.path + EncodeUtil.encodeUrlPart(destName));
292+
293+
// If an item with the same name exists in target directory - remove it.
294+
try {
295+
const item = await this.context.getHierarchyItem(targetPath);
296+
if (item != null) {
297+
await item.delete(multistatus);
298+
}
299+
300+
} catch (err) {
301+
// Report exception to client and continue with other items by returning from recursion.
302+
multistatus.addInnerException(targetPath, undefined, err);
303+
304+
return;
305+
}
306+
307+
// Move the file.
308+
await promisify(rename)(this.directory, newDirPath);
283309
}
284310
//$>
285311

FileSystem/DavFolder.js

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const DavHierarchyItem_1 = require("./DavHierarchyItem");
88
const DavException_1 = require("ithit.webdav.server/DavException");
99
const DavStatus_1 = require("ithit.webdav.server/DavStatus");
1010
const EncodeUtil_1 = require("ithit.webdav.server/EncodeUtil");
11+
const constants_1 = require("constants");
1112
/**
1213
* Folder in WebDAV repository.
1314
*/
@@ -19,9 +20,11 @@ class DavFolder extends DavHierarchyItem_1.DavHierarchyItem {
1920
* @returns Folder instance or null if physical folder not found in file system.
2021
*/
2122
static async getFolder(context, path) {
22-
const folderPath = context.mapPath(path) + path_1.sep + path;
23-
const existFolder = await util_1.promisify(fs_1.exists)(folderPath);
24-
if (!existFolder) {
23+
const folderPath = EncodeUtil_1.EncodeUtil.decodeUrlPart(context.mapPath(path) + path_1.sep + path);
24+
try {
25+
await util_1.promisify(fs_1.access)(folderPath, constants_1.F_OK);
26+
}
27+
catch (err) {
2528
return null;
2629
}
2730
const folder = await util_1.promisify(fs_1.stat)(folderPath);
@@ -150,7 +153,47 @@ class DavFolder extends DavHierarchyItem_1.DavHierarchyItem {
150153
* @param destName New name of this folder.
151154
* @param multistatus Information about child items that failed to move.
152155
*/
153-
moveTo(destFolder, destName, multistatus) {
156+
async moveTo(destFolder, destName, multistatus) {
157+
await this.requireHasToken();
158+
const targetFolder = destFolder;
159+
if (targetFolder == null) {
160+
throw new DavException_1.DavException("Target folder doesn't exist", undefined, DavStatus_1.DavStatus.CONFLICT);
161+
}
162+
if (this.isRecursive(targetFolder)) {
163+
throw new DavException_1.DavException("Cannot move folder to its subtree.", undefined, DavStatus_1.DavStatus.FORBIDDEN);
164+
}
165+
const targetPath = (targetFolder.path + EncodeUtil_1.EncodeUtil.encodeUrlPart(destName));
166+
try {
167+
// Remove item with the same name at destination if it exists.
168+
const item = await this.context.getHierarchyItem(targetPath);
169+
if (item !== null) {
170+
await item.delete(multistatus);
171+
}
172+
await targetFolder.createFolder(destName);
173+
}
174+
catch (err) {
175+
// Continue the operation but report error with destination path to client.
176+
multistatus.addInnerException(targetPath, undefined, err);
177+
return;
178+
}
179+
// Move child items.
180+
let movedSuccessfully = true;
181+
const createdFolder = await this.context.getHierarchyItem(targetPath);
182+
const children = await this.getChildren([new PropertyName_1.PropertyName()]);
183+
for (let i = 0; i < children.length; i++) {
184+
const item = children[i];
185+
try {
186+
await item.moveTo(createdFolder, item.name, multistatus);
187+
}
188+
catch (err) {
189+
// If a child item failed to copy we continue but report error to client.
190+
multistatus.addInnerException(item.path, undefined, err);
191+
movedSuccessfully = false;
192+
}
193+
}
194+
if (movedSuccessfully) {
195+
await this.delete(multistatus);
196+
}
154197
}
155198
/**
156199
* Called whan this folder is being deleted.
@@ -186,6 +229,7 @@ class DavFolder extends DavHierarchyItem_1.DavHierarchyItem {
186229
* @returns List of @see IHierarchyItemAsync satisfying search request.
187230
*/
188231
search(searchString, options, propNames) {
232+
// Not implemented currently.
189233
}
190234
//$>
191235
/**

FileSystem/DavFolder.ts

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { exists, readdir, stat, Stats, mkdir, rmdir, open, close } from "fs";
1+
import { exists, readdir, stat, Stats, mkdir, rmdir, open, close, access } from "fs";
22
import { IFolder } from "ithit.webdav.server/Class1/IFolder";
33
import { IHierarchyItem } from "ithit.webdav.server/IHierarchyItem";
44
import { IItemCollection } from "ithit.webdav.server/IItemCollection";
@@ -11,6 +11,7 @@ import { DavHierarchyItem } from "./DavHierarchyItem";
1111
import { DavException } from "ithit.webdav.server/DavException";
1212
import { DavStatus } from "ithit.webdav.server/DavStatus";
1313
import { EncodeUtil } from "ithit.webdav.server/EncodeUtil";
14+
import { F_OK } from "constants";
1415

1516
/**
1617
* Folder in WebDAV repository.
@@ -23,9 +24,10 @@ export class DavFolder extends DavHierarchyItem implements IFolder {
2324
* @returns Folder instance or null if physical folder not found in file system.
2425
*/
2526
public static async getFolder(context: DavContext, path: string): Promise<DavFolder | null> {
26-
const folderPath: string = context.mapPath(path) + sep + path;
27-
const existFolder = await promisify(exists)(folderPath);
28-
if (!existFolder) {
27+
const folderPath: string = EncodeUtil.decodeUrlPart(context.mapPath(path) + sep + path);
28+
try {
29+
await promisify(access)(folderPath, F_OK);
30+
} catch(err) {
2931
return null;
3032
}
3133

@@ -170,7 +172,51 @@ export class DavFolder extends DavHierarchyItem implements IFolder {
170172
* @param destName New name of this folder.
171173
* @param multistatus Information about child items that failed to move.
172174
*/
173-
public moveTo(destFolder: IItemCollection, destName: string, multistatus: MultistatusException): void {
175+
public async moveTo(destFolder: IItemCollection, destName: string, multistatus: MultistatusException): Promise<void> {
176+
await this.requireHasToken();
177+
const targetFolder = destFolder as DavFolder;
178+
if (targetFolder == null) {
179+
throw new DavException("Target folder doesn't exist", undefined, DavStatus.CONFLICT);
180+
}
181+
182+
if (this.isRecursive(targetFolder)) {
183+
throw new DavException("Cannot move folder to its subtree.", undefined, DavStatus.FORBIDDEN);
184+
}
185+
186+
const targetPath = (targetFolder.path + EncodeUtil.encodeUrlPart(destName));
187+
try {
188+
// Remove item with the same name at destination if it exists.
189+
const item = await this.context.getHierarchyItem(targetPath);
190+
if (item !== null) {
191+
await item.delete(multistatus);
192+
}
193+
194+
await targetFolder.createFolder(destName);
195+
} catch (err) {
196+
// Continue the operation but report error with destination path to client.
197+
multistatus.addInnerException(targetPath, undefined, err);
198+
return;
199+
}
200+
201+
// Move child items.
202+
let movedSuccessfully = true;
203+
const createdFolder = await this.context.getHierarchyItem(targetPath);
204+
const children = await this.getChildren([new PropertyName()]);
205+
for(let i = 0; i < children.length; i++) {
206+
const item = children[i];
207+
208+
try {
209+
await item.moveTo(createdFolder as IItemCollection, item.name, multistatus);
210+
} catch (err) {
211+
// If a child item failed to copy we continue but report error to client.
212+
multistatus.addInnerException(item.path, undefined, err);
213+
movedSuccessfully = false;
214+
}
215+
}
216+
217+
if (movedSuccessfully) {
218+
await this.delete(multistatus);
219+
}
174220
}
175221

176222
/**
@@ -208,6 +254,7 @@ export class DavFolder extends DavHierarchyItem implements IFolder {
208254
* @returns List of @see IHierarchyItemAsync satisfying search request.
209255
*/
210256
public search(searchString: string, options: any, propNames: PropertyName[]): void {
257+
// Not implemented currently.
211258
}
212259
//$>
213260

0 commit comments

Comments
 (0)