UNPKG

node-smb-server

Version:

A Pure JavaScript SMB Server Implementation

289 lines (252 loc) 8.17 kB
/* * Copyright 2015 Adobe Systems Incorporated. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ 'use strict'; var logger = require('winston').loggers.get('spi'), async = require('async'); var common = require('./common'); /** * Represents a file opened by an SMB command. * * @param {File} spiFile * @param {SMBTree} smbTree * @param {Number} [createAction = FILE_OPENED] * @param {Number} [fid = 0] * @constructor */ function SMBFile(spiFile, smbTree, createAction, fid) { this.spiFile = spiFile; this.smbTree = smbTree; this.createAction = createAction === undefined ? common.FILE_OPENED : createAction; this.attributes = 0; if (spiFile.isDirectory()) { this.attributes |= common.ATTR_DIRECTORY; } else if (spiFile.isFile()) { this.attributes |= common.ATTR_NORMAL; } if (spiFile.isHidden()) { this.attributes |= common.ATTR_HIDDEN; } if (spiFile.isReadOnly()) { this.attributes |= common.ATTR_READ_ONLY; } this.fid = fid === undefined ? 0 : fid; this.deleteOnClose = false; } SMBFile.prototype.getId = function () { return this.fid; }; SMBFile.prototype.getTree = function () { return this.smbTree; }; SMBFile.prototype.getCreateAction = function () { return this.createAction; }; SMBFile.prototype.getAttributes = function () { return this.attributes; }; /** * Return the file name. * * @return {String} file name */ SMBFile.prototype.getName = function () { return this.spiFile.getName(); }; /** * Return the file path. * * @return {String} file path */ SMBFile.prototype.getPath = function () { return this.spiFile.getPath(); }; /** * Return a flag indicating whether this is a file. * * @return {Boolean} <code>true</code> if this is a file; * <code>false</code> otherwise */ SMBFile.prototype.isFile = function () { return this.spiFile.isFile(); }; /** * Return a flag indicating whether this is a directory. * * @return {Boolean} <code>true</code> if this is a directory; * <code>false</code> otherwise */ SMBFile.prototype.isDirectory = function () { return this.spiFile.isDirectory(); }; /** * Return a flag indicating whether this file is read-only. * * @return {Boolean} <code>true</code> if this file is read-only; * <code>false</code> otherwise */ SMBFile.prototype.isReadOnly = function () { return this.spiFile.isReadOnly(); }; /** * Return the file length in bytes or 0 in the case of a directory. * * @return {Number} file length, in bytes */ SMBFile.prototype.getDataSize = function () { return this.spiFile.isFile() ? this.spiFile.size() : 0; }; /** * Return the number of bytes that are allocated to the file or 0 in the case of a directory. * * @return {Number} allocation size, in bytes */ SMBFile.prototype.getAllocationSize = function () { return this.spiFile.isFile() ? this.spiFile.allocationSize() : 0; }; /** * Return the create time, in milliseconds since Jan 1, 1970, 00:00:00.0. * * @return {Number} time created */ SMBFile.prototype.getCreatedTime = function () { return this.spiFile.created(); }; /** * Return the time of last modification, in milliseconds since * Jan 1, 1970, 00:00:00.0. * * @return {Number} time created */ SMBFile.prototype.getLastModifiedTime = function () { return this.spiFile.lastModified(); }; /** * Sets the time of last modification, in milliseconds since * Jan 1, 1970, 00:00:00.0. * * @param {Number} ms * @return {Number} time of last modification */ SMBFile.prototype.setLastModifiedTime = function (ms) { this.spiFile.setLastModified(ms); }; /** * Return the time when file status was last changed, in milliseconds since * Jan 1, 1970, 00:00:00.0. * * @return {Number} when file status was last changed */ SMBFile.prototype.getLastChangedTime = function () { return this.spiFile.lastChanged(); }; /** * Return the time of last access, in milliseconds since Jan 1, 1970, 00:00:00.0. * * @return {Number} time of last access */ SMBFile.prototype.getLastAccessedTime = function () { return this.spiFile.lastAccessed(); }; /** * Read bytes at a certain position inside the file. * * @param {Buffer} buffer the buffer that the data will be written to * @param {Number} offset the offset in the buffer to start writing at * @param {Number} length the number of bytes to read * @param {Number} position offset where to begin reading from in the file * @param {Function} cb callback called with the bytes actually read * @param {SMBError} cb.error error (non-null if an error occurred) * @param {Number} cb.bytesRead number of bytes actually read * @param {Buffer} cb.buffer buffer holding the bytes actually read */ SMBFile.prototype.read = function (buffer, offset, length, position, cb) { logger.debug('[fid=%d] file.read %s offset=%d, length=%d, position=%d', this.fid, this.getPath(), offset, length, position); this.spiFile.read(buffer, offset, length, position, cb); }; /** * Write bytes at a certain position inside the file. * * @param {Buffer} data buffer to write * @param {Number} position position inside file * @param {Function} cb callback called on completion * @param {SMBError} cb.error error (non-null if an error occurred) */ SMBFile.prototype.write = function (data, position, cb) { logger.debug('[fid=%d] file.write %s data.length=%d, position=%d', this.fid, this.getPath(), data.length, position); this.spiFile.write(data, position, cb); }; /** * Delete this file or directory. If this file denotes a directory, it must * be empty in order to be deleted. * * @param {Function} cb callback called on completion * @param {SMBError} cb.error error (non-null if an error occurred) */ SMBFile.prototype.delete = function (cb) { logger.debug('[fid=%d] file.delete %s', this.fid, this.getPath()); this.spiFile.delete(cb); // notify registered change listeners this.smbTree.notifyChangeListeners(common.FILE_ACTION_REMOVED, this.getPath()); }; /** * Sets the length of the file. * * @param {Number} length new length of file * @param {Function} cb callback called on completion * @param {SMBError} cb.error error (non-null if an error occurred) */ SMBFile.prototype.setLength = function (length, cb) { logger.debug('[fid=%d] file.setLength %s length=%d', this.fid, this.getPath(), length); this.spiFile.setLength(length, cb); }; /** * Delete this file when it will be closed. */ SMBFile.prototype.setDeleteOnClose = function () { logger.debug('[fid=%d] file.setDeleteOnClose %s', this.fid, this.getPath()); this.deleteOnClose = true; }; /** * Flush the contents of the file to disk. * * @param {Function} cb callback called on completion * @param {SMBError} cb.error error (non-null if an error occurred) */ SMBFile.prototype.flush = function (cb) { logger.debug('[fid=%d] file.flush %s', this.fid, this.getPath()); this.spiFile.flush(cb); // notify registered change listeners this.smbTree.notifyChangeListeners(common.FILE_ACTION_MODIFIED, this.getPath()); }; /** * Close this file, releasing any resources. * * @param {Function} cb callback called on completion * @param {SMBError} cb.error error (non-null if an error occurred) */ SMBFile.prototype.close = function (cb) { logger.debug('[fid=%d] file.close %s deleteOnClose=%d', this.fid, this.getPath(), this.deleteOnClose); var self = this; async.series([ function (callback) { self.spiFile.close(callback); }, function (callback) { if (self.deleteOnClose) { self.delete(callback); } else { callback(); } } ], cb); }; module.exports = SMBFile;