Skip to content

Commit

Permalink
Add file stat commands
Browse files Browse the repository at this point in the history
  • Loading branch information
nullobsi committed Dec 25, 2020
1 parent 1211da6 commit e0e5a7a
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 8 deletions.
111 changes: 105 additions & 6 deletions classes/FTPClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,106 @@ class FTPClient implements Deno.Closer {
this.lock.unlock();
}

//naive way of doing this but there isn't really another way that works on everything
//TODO: use feat command and use MLST if available
/**
* Obtain file information from the FTP server.
* @param filename
*/
public async stat(filename: string): Promise<Deno.FileInfo> {
let retn: Deno.FileInfo = {
atime: null,
birthtime: null,
blksize: null,
blocks: null,
dev: null,
gid: null,
ino: null,
mode: null,
nlink: null,
rdev: null,
uid: null,

mtime: null,
isSymlink: false,
isFile: true,
isDirectory: false,
size: 0
}


try {
retn.size = await this.size(filename);
} catch (e) {
if (e.code !== 550) {
throw e;
} else {
retn.isDirectory = true;
retn.isFile = false;
}
}

if (retn.isFile) {
retn.mtime = await this.modified(filename);
}

return retn;
}

/**
* Get file size in bytes
* @param filename
*/
public async size(filename: string): Promise<number> {
await this.lock.lock();
if (this.conn === undefined) {
this.lock.unlock();
throw FTPClient.notInit();
}

let res = await this.command(Commands.Size, filename);
this.assertStatus(StatusCodes.FileStat, res);

this.lock.unlock();
return parseInt(res.message);
}

/**
* Get file modification time.
* @param filename
*/
public async modified(filename: string): Promise<Date> {
await this.lock.lock();
if (this.conn === undefined) {
this.lock.unlock();
throw FTPClient.notInit();
}

let res = await this.command(Commands.ModifiedTime, filename);
this.assertStatus(StatusCodes.FileStat, res);
this.lock.unlock();

let parsed = Regexes.mdtmReply.exec(res.message);
if (parsed && parsed.groups) {
console.log(parsed.groups);
let year = parseInt(parsed.groups.year);
let month = parseInt(parsed.groups.month);
let day = parseInt(parsed.groups.day);
let hour = parseInt(parsed.groups.hour);
let minute = parseInt(parsed.groups.minute);
let second = parseInt(parsed.groups.second);
let ms = parsed.groups.ms;
let date = new Date(year, month, day, hour, minute, second);
if (ms !== undefined) {
let n = parseFloat(ms);
date.setMilliseconds(n*1000);
}
return date;
} else {
throw res;
}
}


/**
* Rename a file on the server.
Expand Down Expand Up @@ -370,7 +470,7 @@ class FTPClient implements Deno.Closer {

let conn = await this.finalizeDataConnection();
let data = await FTPClient.recieve(conn);
conn.close();
free(conn);

res = await this.getStatus();
this.assertStatus(StatusCodes.DataClose, res);
Expand All @@ -388,10 +488,9 @@ class FTPClient implements Deno.Closer {
*/
public async close() {
await this.lock.lock();
if (this.conn) {
await this.command(Commands.Quit);
this.conn.close();
}
free(this.conn);
free(this.activeListener);
free(this.dataConn);
this.lock.unlock();
}

Expand Down Expand Up @@ -478,7 +577,7 @@ class FTPClient implements Deno.Closer {
private async finalizeDataConnection() {
if (this.opts.mode == "active") {
this.dataConn = await this.activeListener?.accept();
this.activeListener?.close();
free(this.activeListener);
}
if (this.dataConn === undefined) throw new Error("Could not initialize data connection!");
if (this.opts.tlsOpts)
Expand Down
6 changes: 5 additions & 1 deletion util/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ enum Commands {

Auth = "AUTH",
Protection = "PROT",

Size = "SIZE",
ModifiedTime = "MDTM",
}

enum Types {
Expand All @@ -40,7 +43,8 @@ enum StatusCodes {
NotImpOK = 202,
SysStatus = 211,
DirStatus,
HelpMessage = 214,
FileStat,
HelpMessage,
SysType,

Ready = 220,
Expand Down
3 changes: 2 additions & 1 deletion util/regexes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const passivePort = /\([\x21-\x7E][\x21-\x7E][\x21-\x7E](?<port>[0-9]+)[\x21-\x7E]\)/
const path = /"(.+)"/

const mdtmReply = /(?<year>[0-9]{4})(?<month>[0-9]{2})(?<day>[0-9]{2})(?<hour>[0-9]{2})(?<minute>[0-9]{2})(?<second>[0-9]{2})(?<ms>\.[0-9]+)?/;
export {
passivePort,
path,
mdtmReply,
}

0 comments on commit e0e5a7a

Please sign in to comment.