Example #1
0
        /// <summary>
        /// Calculates the permissions flags from the CHMOD value
        /// </summary>
        public static void CalculateUnixPermissions(this FtpListItem item, string permissions)
        {
            var perms = Regex.Match(permissions,
                                    @"[\w-]{1}(?<owner>[\w-]{3})(?<group>[\w-]{3})(?<others>[\w-]{3})",
                                    RegexOptions.IgnoreCase);

            if (perms.Success)
            {
                if (perms.Groups["owner"].Value.Length == 3)
                {
                    if (perms.Groups["owner"].Value[0] == 'r')
                    {
                        item.OwnerPermissions |= FtpPermission.Read;
                    }

                    if (perms.Groups["owner"].Value[1] == 'w')
                    {
                        item.OwnerPermissions |= FtpPermission.Write;
                    }

                    if (perms.Groups["owner"].Value[2] == 'x' || perms.Groups["owner"].Value[2] == 's')
                    {
                        item.OwnerPermissions |= FtpPermission.Execute;
                    }

                    if (perms.Groups["owner"].Value[2] == 's' || perms.Groups["owner"].Value[2] == 'S')
                    {
                        item.SpecialPermissions |= FtpSpecialPermissions.SetUserID;
                    }
                }

                if (perms.Groups["group"].Value.Length == 3)
                {
                    if (perms.Groups["group"].Value[0] == 'r')
                    {
                        item.GroupPermissions |= FtpPermission.Read;
                    }

                    if (perms.Groups["group"].Value[1] == 'w')
                    {
                        item.GroupPermissions |= FtpPermission.Write;
                    }

                    if (perms.Groups["group"].Value[2] == 'x' || perms.Groups["group"].Value[2] == 's')
                    {
                        item.GroupPermissions |= FtpPermission.Execute;
                    }

                    if (perms.Groups["group"].Value[2] == 's' || perms.Groups["group"].Value[2] == 'S')
                    {
                        item.SpecialPermissions |= FtpSpecialPermissions.SetGroupID;
                    }
                }

                if (perms.Groups["others"].Value.Length == 3)
                {
                    if (perms.Groups["others"].Value[0] == 'r')
                    {
                        item.OthersPermissions |= FtpPermission.Read;
                    }

                    if (perms.Groups["others"].Value[1] == 'w')
                    {
                        item.OthersPermissions |= FtpPermission.Write;
                    }

                    if (perms.Groups["others"].Value[2] == 'x' || perms.Groups["others"].Value[2] == 't')
                    {
                        item.OthersPermissions |= FtpPermission.Execute;
                    }

                    if (perms.Groups["others"].Value[2] == 't' || perms.Groups["others"].Value[2] == 'T')
                    {
                        item.SpecialPermissions |= FtpSpecialPermissions.Sticky;
                    }
                }

                CalculateChmod(item);
            }
        }
Example #2
0
        /// <summary>
        /// Get the full path of a given FTP Listing entry
        /// </summary>
        public static void CalculateFullFtpPath(this FtpListItem item, FtpClient client, string path, bool isVMS)
        {
            // EXIT IF NO DIR PATH PROVIDED
            if (path == null)
            {
                // check if the path is absolute
                if (IsAbsolutePath(item.Name))
                {
                    item.FullName = item.Name;
                    item.Name     = item.Name.GetFtpFileName();
                }

                return;
            }


            // ONLY IF DIR PATH PROVIDED

            // if this is a vax/openvms file listing
            // there are no slashes in the path name
            if (isVMS)
            {
                item.FullName = path + item.Name;
            }
            else
            {
                //this.client.LogStatus(item.Name);

                // remove globbing/wildcard from path
                if (path.GetFtpFileName().Contains("*"))
                {
                    path = path.GetFtpDirectoryName();
                }

                if (item.Name != null)
                {
                    // absolute path? then ignore the path input to this method.
                    if (IsAbsolutePath(item.Name))
                    {
                        item.FullName = item.Name;
                        item.Name     = item.Name.GetFtpFileName();
                    }
                    else if (path != null)
                    {
                        item.FullName = path.GetFtpPath(item.Name);                         //.GetFtpPathWithoutGlob();
                    }
                    else
                    {
                        client.LogStatus(FtpTraceLevel.Warn, "Couldn't determine the full path of this object: " +
                                         Environment.NewLine + item.ToString());
                    }
                }


                // if a link target is set and it doesn't include an absolute path
                // then try to resolve it.
                if (item.LinkTarget != null && !item.LinkTarget.StartsWith("/"))
                {
                    if (item.LinkTarget.StartsWith("./"))
                    {
                        item.LinkTarget = path.GetFtpPath(item.LinkTarget.Remove(0, 2)).Trim();
                    }
                    else
                    {
                        item.LinkTarget = path.GetFtpPath(item.LinkTarget).Trim();
                    }
                }
            }
        }
Example #3
0
 /// <summary>
 /// Calculates the CHMOD value from the permissions flags
 /// </summary>
 public static void CalculateChmod(this FtpListItem item)
 {
     item.Chmod = CalcChmod(item.OwnerPermissions, item.GroupPermissions, item.OthersPermissions);
 }
Example #4
0
        /// <summary>
        /// Returns true if the file passes all the rules
        /// </summary>
        private bool FilePassesRules(FtpResult result, List <FtpRule> rules, bool useLocalPath, FtpListItem item = null)
        {
            if (rules != null && rules.Count > 0)
            {
                var passes = FtpRule.IsAllAllowed(rules, item ?? result.ToListItem(useLocalPath));
                if (!passes)
                {
                    LogStatus(FtpTraceLevel.Info, "Skipped file due to rule: " + (useLocalPath ? result.LocalPath : result.RemotePath));

                    // mark that the file was skipped due to a rule
                    result.IsSkipped       = true;
                    result.IsSkippedByRule = true;

                    // skip uploading the file
                    return(false);
                }
            }
            return(true);
        }
Example #5
0
        /// <summary>
        /// Gets a file listing from the server asynchronously. Each <see cref="FtpListItem"/> object returned
        /// contains information about the file that was able to be retrieved.
        /// </summary>
        /// <remarks>
        /// If a <see cref="DateTime"/> property is equal to <see cref="DateTime.MinValue"/> then it means the
        /// date in question was not able to be retrieved. If the <see cref="FtpListItem.Size"/> property
        /// is equal to 0, then it means the size of the object could also not
        /// be retrieved.
        /// </remarks>
        /// <param name="path">The path to list</param>
        /// <param name="options">Options that dictate how the list operation is performed</param>
        /// <returns>An array of items retrieved in the listing</returns>
        public async Task <FtpListItem[]> GetListingAsync(string path, FtpListOption options)
        {
            //TODO:  Add cancellation support
            FtpTrace.WriteFunc(nameof(GetListingAsync), new object[] { path, options });

            FtpListItem        item       = null;
            List <FtpListItem> lst        = new List <FtpListItem>();
            List <string>      rawlisting = new List <string>();
            string             listcmd    = null;
            string             buf        = null;

            // read flags
            bool isIncludeSelf = (options & FtpListOption.IncludeSelfAndParent) == FtpListOption.IncludeSelfAndParent;
            bool isForceList   = (options & FtpListOption.ForceList) == FtpListOption.ForceList;
            bool isNoPath      = (options & FtpListOption.NoPath) == FtpListOption.NoPath;
            bool isNameList    = (options & FtpListOption.NameList) == FtpListOption.NameList;
            bool isUseLS       = (options & FtpListOption.UseLS) == FtpListOption.UseLS;
            bool isAllFiles    = (options & FtpListOption.AllFiles) == FtpListOption.AllFiles;
            bool isRecursive   = (options & FtpListOption.Recursive) == FtpListOption.Recursive && RecursiveList;
            bool isDerefLinks  = (options & FtpListOption.DerefLinks) == FtpListOption.DerefLinks;
            bool isGetModified = (options & FtpListOption.Modify) == FtpListOption.Modify;
            bool isGetSize     = (options & FtpListOption.Size) == FtpListOption.Size;

            // calc path to request
            path = await GetAbsolutePathAsync(path);

            // MLSD provides a machine readable format with 100% accurate information
            // so always prefer MLSD over LIST unless the caller of this method overrides it with the ForceList option
            bool machineList = false;

            if ((!isForceList || m_parser == FtpParser.Machine) && HasFeature(FtpCapability.MLSD))
            {
                listcmd     = "MLSD";
                machineList = true;
            }
            else
            {
                if (isUseLS)
                {
                    listcmd = "LS";
                }
                else if (isNameList)
                {
                    listcmd = "NLST";
                }
                else
                {
                    string listopts = "";

                    listcmd = "LIST";

                    if (isAllFiles)
                    {
                        listopts += "a";
                    }

                    if (isRecursive)
                    {
                        listopts += "R";
                    }

                    if (listopts.Length > 0)
                    {
                        listcmd += " -" + listopts;
                    }
                }
            }

            if (!isNoPath)
            {
                listcmd = (listcmd + " " + path.GetFtpPath());
            }

            await ExecuteAsync("TYPE I");

            // read in raw file listing
            using (FtpDataStream stream = await OpenDataStreamAsync(listcmd, 0))
            {
                try
                {
                    FtpTrace.WriteLine(FtpTraceLevel.Verbose, "+---------------------------------------+");

                    if (this.BulkListing)
                    {
                        // increases performance of GetListing by reading multiple lines of the file listing at once
                        foreach (var line in await stream.ReadAllLinesAsync(Encoding, this.BulkListingLength))
                        {
                            if (!FtpExtensions.IsNullOrWhiteSpace(line))
                            {
                                rawlisting.Add(line);
                                FtpTrace.WriteLine(FtpTraceLevel.Verbose, "Listing:  " + line);
                            }
                        }
                    }
                    else
                    {
                        // GetListing will read file listings line-by-line (actually byte-by-byte)
                        while ((buf = await stream.ReadLineAsync(Encoding)) != null)
                        {
                            if (buf.Length > 0)
                            {
                                rawlisting.Add(buf);
                                FtpTrace.WriteLine(FtpTraceLevel.Verbose, "Listing:  " + buf);
                            }
                        }
                    }

                    FtpTrace.WriteLine(FtpTraceLevel.Verbose, "-----------------------------------------");
                }
                finally
                {
                    stream.Close();
                }
            }

            for (int i = 0; i < rawlisting.Count; i++)
            {
                buf = rawlisting[i];

                if (isNameList)
                {
                    // if NLST was used we only have a file name so
                    // there is nothing to parse.
                    item = new FtpListItem()
                    {
                        FullName = buf
                    };

                    if (await DirectoryExistsAsync(item.FullName))
                    {
                        item.Type = FtpFileSystemObjectType.Directory;
                    }
                    else
                    {
                        item.Type = FtpFileSystemObjectType.File;
                    }

                    lst.Add(item);
                }
                else
                {
                    // if this is a result of LIST -R then the path will be spit out
                    // before each block of objects
                    if (listcmd.StartsWith("LIST") && isRecursive)
                    {
                        if (buf.StartsWith("/") && buf.EndsWith(":"))
                        {
                            path = buf.TrimEnd(':');
                            continue;
                        }
                    }

                    // if the next line in the listing starts with spaces
                    // it is assumed to be a continuation of the current line
                    if (i + 1 < rawlisting.Count && (rawlisting[i + 1].StartsWith("\t") || rawlisting[i + 1].StartsWith(" ")))
                    {
                        buf += rawlisting[++i];
                    }

                    try
                    {
                        item = m_listParser.ParseSingleLine(path, buf, m_caps, machineList);
                    }
                    catch (FtpListParser.CriticalListParseException)
                    {
                        FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Restarting parsing from first entry in list");
                        i = -1;
                        lst.Clear();
                        continue;
                    }

                    // FtpListItem.Parse() returns null if the line
                    // could not be parsed
                    if (item != null)
                    {
                        if (isIncludeSelf || !(item.Name == "." || item.Name == ".."))
                        {
                            lst.Add(item);
                        }
                        else
                        {
                            //FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Skipped self or parent item: " + item.Name);
                        }
                    }
                    else
                    {
                        FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Failed to parse file listing: " + buf);
                    }
                }

                // load extended information that wasn't available if the list options flags say to do so.
                if (item != null)
                {
                    // try to dereference symbolic links if the appropriate list
                    // option was passed
                    if (item.Type == FtpFileSystemObjectType.Link && isDerefLinks)
                    {
                        item.LinkObject = await DereferenceLinkAsync(item);
                    }

                    // if need to get file modified date
                    if (isGetModified && HasFeature(FtpCapability.MDTM))
                    {
                        // if the modified date was not loaded or the modified date is more than a day in the future
                        // and the server supports the MDTM command, load the modified date.
                        // most servers do not support retrieving the modified date
                        // of a directory but we try any way.
                        if (item.Modified == DateTime.MinValue || listcmd.StartsWith("LIST"))
                        {
                            DateTime modify;

                            if (item.Type == FtpFileSystemObjectType.Directory)
                            {
                                FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Trying to retrieve modification time of a directory, some servers don't like this...");
                            }

                            if ((modify = await GetModifiedTimeAsync(item.FullName)) != DateTime.MinValue)
                            {
                                item.Modified = modify;
                            }
                        }
                    }

                    // if need to get file size
                    if (isGetSize && HasFeature(FtpCapability.SIZE))
                    {
                        // if no size was parsed, the object is a file and the server
                        // supports the SIZE command, then load the file size
                        if (item.Size == -1)
                        {
                            if (item.Type != FtpFileSystemObjectType.Directory)
                            {
                                item.Size = await GetFileSizeAsync(item.FullName);
                            }
                            else
                            {
                                item.Size = 0;
                            }
                        }
                    }
                }
            }

            return(lst.ToArray());
        }
Example #6
0
        /// <summary>
        /// Returns information about a file system object. Returns null if the server response can't
        /// be parsed or the server returns a failure completion code. The error for a failure
        /// is logged with FtpTrace. No exception is thrown on error because that would negate
        /// the usefulness of this method for checking for the existence of an object.
        /// </summary>
        /// <param name="path">The path of the file or folder</param>
        /// <param name="dateModified">Get the accurate modified date using another MDTM command</param>
        /// <returns>A FtpListItem object</returns>
        public FtpListItem GetObjectInfo(string path, bool dateModified = false)
        {
            // verify args
            if (path.IsBlank())
            {
                throw new ArgumentException("Required parameter is null or blank.", "path");
            }

            FtpTrace.WriteFunc("GetObjectInfo", new object[] { path, dateModified });

            FtpReply reply;

            string[] res;

            bool supportsMachineList = (Capabilities & FtpCapability.MLSD) == FtpCapability.MLSD;

            FtpListItem result = null;

            if (supportsMachineList)
            {
                // USE MACHINE LISTING TO GET INFO FOR A SINGLE FILE

                if ((reply = Execute("MLST " + path)).Success)
                {
                    res = reply.InfoMessages.Split('\n');
                    if (res.Length > 1)
                    {
                        string info = "";

                        for (int i = 1; i < res.Length; i++)
                        {
                            info += res[i];
                        }

                        result = m_listParser.ParseSingleLine(null, info, m_caps, true);
                    }
                }
                else
                {
                    FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Failed to get object info for path " + path + " with error " + reply.ErrorMessage);
                }
            }
            else
            {
                // USE GETLISTING TO GET ALL FILES IN DIR .. SLOWER BUT AT LEAST IT WORKS

                string        dirPath  = path.GetFtpDirectoryName();
                FtpListItem[] dirItems = GetListing(dirPath);

                foreach (var dirItem in dirItems)
                {
                    if (dirItem.FullName == path)
                    {
                        result = dirItem;
                        break;
                    }
                }

                FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Failed to get object info for path " + path + " since MLST not supported and GetListing() fails to list file/folder.");
            }

            // Get the accurate date modified using another MDTM command
            if (result != null && dateModified && HasFeature(FtpCapability.MDTM))
            {
                result.Modified = GetModifiedTime(path);
            }

            return(result);
        }
Example #7
0
        /// <summary>
        /// Retrieve the permissions of the given file/folder as an integer in the CHMOD format.
        /// Throws FtpCommandException if there is an issue.
        /// Returns 0 if the server did not specify a permission value.
        /// Use `GetFilePermissions` if you required the permissions in the FtpPermission format.
        /// </summary>
        /// <param name="path">The full or relative path to the item</param>
        /// <param name="token">The token that can be used to cancel the entire process</param>
        public async Task <int> GetChmodAsync(string path, CancellationToken token = default(CancellationToken))
        {
            FtpListItem item = await GetFilePermissionsAsync(path, token);

            return(item != null ? item.Chmod : 0);
        }
Example #8
0
        /// <summary>
        /// Parse raw file from server into a file object, using the currently active parser.
        /// </summary>
        public FtpListItem ParseSingleLine(string path, string file, List <FtpCapability> caps, bool isMachineList)
        {
            FtpListItem result = null;

            // force machine listing if it is
            if (isMachineList)
            {
                result = FtpMachineListParser.Parse(file, caps, client);
            }
            else
            {
                // use custom parser if given
                if (m_customParser != null)
                {
                    result = m_customParser(file, caps, client);
                }
                else
                {
                    if (IsWrongParser())
                    {
                        ValidateParser(new[] { file });
                    }

                    // use one of the in-built parsers
                    switch (CurrentParser)
                    {
                    case FtpParser.Legacy:
                        result = ParseLegacy(path, file, caps, client);
                        break;

                    case FtpParser.Machine:
                        result = FtpMachineListParser.Parse(file, caps, client);
                        break;

                    case FtpParser.Windows:
                        result = FtpWindowsParser.Parse(client, file);
                        break;

                    case FtpParser.Unix:
                        result = FtpUnixParser.Parse(client, file);
                        break;

                    case FtpParser.UnixAlt:
                        result = FtpUnixParser.ParseUnixAlt(client, file);
                        break;

                    case FtpParser.VMS:
                        result = FtpVMSParser.Parse(client, file);
                        break;

                    case FtpParser.IBM:
                        result = FtpIBMParser.Parse(client, file);
                        break;

                    case FtpParser.NonStop:
                        result = FtpNonStopParser.Parse(client, file);
                        break;
                    }
                }
            }

            // if parsed file successfully
            if (result != null)
            {
                // apply time difference between server/client
                if (HasTimeOffset)
                {
                    result.Modified = result.Modified - TimeOffset;
                }

                // calc absolute file paths
                result.CalculateFullFtpPath(client, path, false);
            }

            return(result);
        }