Example #1
0
        public void SendDirectory(IoStream ioStream, List <FileStruct> fileList, string dir)
        {
            var directoryInfo = new DirectoryInfo(dir);

            if (directoryInfo.Exists)
            {
                if (_options.CvsExclude)
                {
                    var excl = new Exclude(_options);
                    excl.AddExcludeFile(ref _options.LocalExcludeList, dir, (int)(Options.XflgWordSplit & Options.XflgWordsOnly)); //@todo (int)(Options.XFLG_WORD_SPLIT & Options.XFLG_WORDS_ONLY) evaluates to 0 unconditionally. May be change & with | ?
                }
                var files = directoryInfo.GetFiles();
                for (var i = 0; i < files.Length; i++)
                {
                    // TODO: path length
                    SendFileName(ioStream, fileList, files[i].FullName.Replace(@"\", "/"), _options.Recurse, 0);
                }
                var dirs = directoryInfo.GetDirectories();
                for (var i = 0; i < dirs.Length; i++)
                {
                    // TODO: path length
                    SendFileName(ioStream, fileList, dirs[i].FullName.Replace(@"\", "/"), _options.Recurse, 0);
                }
            }
            else
            {
                Log.WriteLine("Can't find directory '" + Util.FullFileName(dir) + "'");
            }
        }
Example #2
0
 public void SendToken(IoStream f, int token, MapFile buf, int offset, int n, int toklen)
 {
     if (!_options.DoCompression)
     {
         SimpleSendToken(f, token, buf, offset, n);
     }
     else
     {
         SendDeflatedToken(f, token, buf, offset, n, toklen);
     }
 }
Example #3
0
        public int ReceiveToken(IoStream ioStream, ref byte[] data, int offset)
        {
            int token;

            if (!_options.DoCompression)
            {
                token = SimpleReceiveToken(ioStream, ref data, offset);
            }
            else
            {
                token = ReceiveDeflatedToken(ioStream, data, offset);
            }
            return(token);
        }
Example #4
0
 public void WriteSumHead(IoStream f, SumStruct sum)
 {
     if (sum == null)
     {
         sum = new SumStruct();
     }
     f.WriteInt(sum.Count);
     f.WriteInt((int)sum.BLength);
     if (_options.ProtocolVersion >= 27)
     {
         f.WriteInt(sum.S2Length);
     }
     f.WriteInt((int)sum.Remainder);
 }
Example #5
0
        public void MatchReport(IoStream f)
        {
            if (_options.Verbose <= 1)
            {
                return;
            }

            var report = "total: matches=" + _totalMatches + "  tagHits=" + _totalTagHits + "  falseAlarms=" +
                         _totalFalseAlarms + " data=" + Options.Stats.LiteralData;

            Log.WriteLine(report);
            if (_options.AmServer)
            {
                f.MultiplexWrite(MsgCode.MsgInfo, Encoding.ASCII.GetBytes(report), report.Length);
            }
        }
Example #6
0
        public static IoStream OpenSocketOut(string host, int port, string bindAddress)
        {
            TcpClient client = null;

            try
            {
                client = new TcpClient(host, port);
            }
            catch (Exception)
            {
                Exit("Can't connect to server", null);
            }
            var stream = new IoStream(client.GetStream());

            return(stream);
        }
Example #7
0
        /// <summary>
        /// Receives exclude list from stream
        /// </summary>
        /// <param name="ioStream"></param>
        public void ReceiveExcludeList(IoStream ioStream)
        {
            var line = String.Empty;
            int length;

            while ((length = ioStream.ReadInt()) != 0)
            {
                if (length >= Options.Maxpathlen + 3)
                {
                    Log.Write("Overflow: recv_exclude_list");
                    continue;
                }

                line = ioStream.ReadStringFromBuffer(length);
                AddExclude(ref _options.ExcludeList, line, 0);
            }
        }
Example #8
0
        public void Matched(IoStream f, SumStruct s, MapFile buf, int offset, int i, Sum sum)
        {
            var n = offset - _lastMatch;
            int j;

            if (_options.Verbose > 2 && i >= 0)
            {
                Log.WriteLine("match at " + offset + " last_match=" + _lastMatch + " j=" + i + " len=" + s.Sums[i].Len + " n=" + n);
            }

            var token = new Token(_options);

            token.SendToken(f, i, buf, _lastMatch, n, (int)(i < 0 ? 0 : s.Sums[i].Len));
            _dataTransfer += n;

            if (i >= 0)
            {
                Options.Stats.MatchedData += s.Sums[i].Len;
                n += (int)s.Sums[i].Len;
            }

            for (j = 0; j < n; j += ChunkSize)
            {
                var n1  = Math.Min(ChunkSize, n - j);
                var off = buf.MapPtr(_lastMatch + j, n1);
                sum.Update(buf.P, off, n1);
            }

            if (i >= 0)
            {
                _lastMatch = (int)(offset + s.Sums[i].Len);
            }
            else
            {
                _lastMatch = offset;
            }

            if (buf != null && _options.DoProgress)
            {
                Progress.ShowProgress(_lastMatch, buf.FileSize);
                if (i == -1)
                {
                    Progress.EndProgress(buf.FileSize);
                }
            }
        }
Example #9
0
 public void SimpleSendToken(IoStream f, int token, MapFile buf, int offset, int n)
 {
     if (n > 0)
     {
         var l = 0;
         while (l < n)
         {
             var n1 = Math.Min(Match.ChunkSize, n - l);
             f.WriteInt(n1);
             var off = buf.MapPtr(offset + l, n1);
             f.Write(buf.P, off, n1);
             l += n1;
         }
     }
     if (token != -2)
     {
         f.WriteInt(-(token + 1));
     }
 }
Example #10
0
        public int SimpleReceiveToken(IoStream ioStream, ref byte[] data, int offset)
        {
            int n;

            if (Residue == 0)
            {
                var i = ioStream.ReadInt();
                if (i <= 0)
                {
                    return(i);
                }
                Residue = i;
            }

            n        = Math.Min(Match.ChunkSize, Residue);
            Residue -= n;
            data     = ioStream.ReadBuffer(n);
            return(n);
        }
Example #11
0
        public void GenerateAndSendSums(Stream fd, long len, IoStream f, Stream fCopy)
        {
            long    i;
            MapFile mapBuf;
            var     sum    = new SumStruct();
            long    offset = 0;

            SumSizesSqroot(sum, (UInt64)len);

            if (len > 0)
            {
                mapBuf = new MapFile(fd, (int)len, Options.MaxMapSize, (int)sum.BLength);
            }
            else
            {
                mapBuf = null;
            }

            WriteSumHead(f, sum);

            for (i = 0; i < sum.Count; i++)
            {
                var n1   = (UInt32)Math.Min(len, sum.BLength);
                var off  = mapBuf.MapPtr((int)offset, (int)n1);
                var map  = mapBuf.P;
                var sum1 = CheckSum.GetChecksum1(map, off, (int)n1);
                var sum2 = new byte[CheckSum.SumLength];

                sum2 = _checkSum.GetChecksum2(map, off, (int)n1);
                if (_options.Verbose > 3)
                {
                    Log.WriteLine("chunk[" + i + "] offset=" + offset + " len=" + n1 + " sum1=" + sum1);
                }
                f.WriteInt((int)sum1);
                f.Write(sum2, 0, sum.S2Length);
                len    -= n1;
                offset += n1;
            }
            if (mapBuf != null)
            {
                mapBuf = null;
            }
        }
Example #12
0
        public void SendExcludeList(IoStream f)
        {
            if (_options.ListOnly && !_options.Recurse)
            {
                AddExclude(ref _options.ExcludeList, "/*/*", 0);
            }

            foreach (var ent in _options.ExcludeList)
            {
                int    l;
                string p;

                if (ent.Pattern.Length == 0 || ent.Pattern.Length > Options.Maxpathlen)
                {
                    continue;
                }
                l = ent.Pattern.Length;
                p = ent.Pattern;
                if ((ent.MatchFlags & Options.MatchflgDirectory) != 0)
                {
                    p += "/\0";
                }

                if ((ent.MatchFlags & Options.MatchflgInclude) != 0)
                {
                    f.WriteInt(l + 2);
                    f.IoPrintf("+ ");
                }
                else if ((p[0] == '-' || p[0] == '+') && p[1] == ' ')
                {
                    f.WriteInt(l + 2);
                    f.IoPrintf("- ");
                }
                else
                {
                    f.WriteInt(l);
                }
                f.IoPrintf(p);
            }
            f.WriteInt(0);
        }
Example #13
0
        public void SendFileName(IoStream ioStream, List <FileStruct> fileList, string fileName, bool recursive, UInt32 baseFlags)
        {
            var file = MakeFile(fileName, fileList, ioStream == null && _options.DeleteExcluded ? Options.ServerExcludes : Options.AllExcludes);

            if (file == null)
            {
                return;
            }
            EmitFileListProgress(fileList);
            if (!string.IsNullOrEmpty(file.BaseName))
            {
                fileList.Add(file);
                SendFileEntry(file, ioStream, baseFlags);

                if (recursive && Util.S_ISDIR(file.Mode) && (file.Flags & Options.FlagMountPoint) == 0)
                {
                    _options.LocalExcludeList.Clear();
                    SendDirectory(ioStream, fileList, file.GetFullName());
                }
            }
        }
Example #14
0
        public void ReceiveGenerator(string fileName, FileStruct file, int i, IoStream f)
        {
            fileName = Path.Combine(_options.Dir, fileName);

            if (UnchangedFile(fileName, file))
            {
                return;
            }
            if (_options.Verbose > 2)
            {
                Log.WriteLine("Receive Generator(" + fileName + "," + i + ")\n");
            }
            int statRet;
            var st = new FStat();

            if (_options.DryRun)
            {
                statRet = -1;
            }
            else
            {
                statRet = 0;
                try
                {
                    var fi = new FileInfo(fileName);
                    // TODO: path length
                    st.Size = fi.Length;
                    // TODO: path length
                    st.MTime = fi.LastWriteTime;
                }
                catch
                {
                    statRet = -1;
                }
            }

            if (_options.OnlyExisting && statRet == -1)
            {
                /* we only want to update existing files */
                if (_options.Verbose > 1)
                {
                    Log.WriteLine("not creating new file \"" + fileName + "\"");
                }
                return;
            }
            var fNameCmp = fileName;

            if (_options.WholeFile > 0)
            {
                f.WriteInt(i);
                WriteSumHead(f, null);
                return;
            }
            FileStream fd;

            try
            {
                fd = new FileStream(fNameCmp, FileMode.Open, FileAccess.Read);
            }
            catch
            {
                if (_options.Verbose > 3)
                {
                    Log.WriteLine("failed to open " + Util.FullFileName(fNameCmp) + ", continuing");
                }
                f.WriteInt(i);
                WriteSumHead(f, null);
                return;
            }

            if (_options.Verbose > 3)
            {
                Log.WriteLine("gen mapped " + fNameCmp + " of size " + st.Size);
            }

            if (_options.Verbose > 2)
            {
                Log.WriteLine("generating and sending sums for " + i);
            }

            f.WriteInt(i);
            Stream fCopy = null;

            GenerateAndSendSums(fd, st.Size, f, fCopy);

            if (fCopy != null)
            {
                fCopy.Close();
            }
            fd.Close();
        }
Example #15
0
        public void GenerateFiles(IoStream f, List <FileStruct> fileList, string localName)
        {
            int i;
            var phase = 0;


            if (_options.Verbose > 2)
            {
                Log.WriteLine("generator starting count=" + fileList.Count);
            }

            for (i = 0; i < fileList.Count; i++)
            {
                var file = (fileList[i]);
                if (file.BaseName == null)
                {
                    continue;
                }
                if (Util.S_ISDIR(file.Mode))
                {
                    continue;
                }
                ReceiveGenerator(localName != null ? localName : file.GetFullName(), file, i, f);
            }

            phase++;
            _checkSum.Length = CheckSum.SumLength;
            if (_options.Verbose > 2)
            {
                Log.WriteLine("GenerateFiles phase=" + phase);
            }
            f.WriteInt(-1);

            phase++;
            if (_options.Verbose > 2)
            {
                Log.WriteLine("GenerateFiles phase=" + phase);
            }

            f.WriteInt(-1);

            if (_options.ProtocolVersion >= 29 && !_options.DelayUpdates)
            {
                f.WriteInt(-1);
            }

            /* now we need to fix any directory permissions that were
             * modified during the transfer
             * */
            for (i = 0; i < fileList.Count; i++)
            {
                var file = (fileList[i]);
                if (file.BaseName != null || Util.S_ISDIR(file.Mode))
                {
                    continue;
                }
                ReceiveGenerator(localName != null ? localName : file.GetFullName(), file, i, null);
            }

            if (_options.Verbose > 2)
            {
                Log.WriteLine("GenerateFiles finished");
            }
        }
Example #16
0
        public void HashSearch(IoStream f, SumStruct s, MapFile buf, int len, Sum _sum)
        {
            int    offset, end, backup;
            UInt32 k;
            int    wantI;
            var    sum2 = new byte[CheckSum.SumLength];
            UInt32 s1, s2, sum;
            int    more;

            byte[] map;

            wantI = 0;
            if (_options.Verbose > 2)
            {
                Log.WriteLine("hash search ob=" + s.BLength + " len=" + len);
            }

            k = (UInt32)Math.Min(len, s.BLength);
            var off = buf.MapPtr(0, (int)k);

            map = buf.P;

            var g = s.Sums[0].Sum1;

            sum = CheckSum.GetChecksum1(map, off, (int)k);
            s1  = sum & 0xFFFF;
            s2  = sum >> 16;
            if (_options.Verbose > 3)
            {
                Log.WriteLine("sum=" + sum + " k=" + k);
            }

            offset = 0;
            end    = (int)(len + 1 - s.Sums[s.Count - 1].Len);
            if (_options.Verbose > 3)
            {
                Log.WriteLine("hash search s.bLength=" + s.BLength + " len=" + len + " count=" + s.Count);
            }

            do
            {
                var t         = GetTag2(s1, s2);
                var doneCsum2 = false;
                var j         = _tagTable[t];

                if (_options.Verbose > 4)
                {
                    Log.WriteLine("offset=" + offset + " sum=" + sum);
                }

                if (j == NullTag)
                {
                    goto null_tag;
                }

                sum = (s1 & 0xffff) | (s2 << 16);
                _tagHits++;
                do
                {
                    UInt32 l;
                    var    i = _targets[j].I;

                    if (sum != s.Sums[i].Sum1)
                    {
                        continue;
                    }

                    l = (UInt32)Math.Min(s.BLength, len - offset);
                    if (l != s.Sums[i].Len)
                    {
                        continue;
                    }

                    if (_options.Verbose > 3)
                    {
                        Log.WriteLine("potential match at " + offset + " target=" + j + " " + i + " sum=" + sum);
                    }

                    if (!doneCsum2)
                    {
                        off = buf.MapPtr(offset, (int)l);
                        map = buf.P;
                        var cs = new CheckSum(_options);
                        sum2      = cs.GetChecksum2(map, off, (int)l);
                        doneCsum2 = true;
                    }

                    if (Util.MemoryCompare(sum2, 0, s.Sums[i].Sum2, 0, s.S2Length) != 0)
                    {
                        _falseAlarms++;
                        continue;
                    }

                    if (i != wantI && wantI < s.Count &&
                        (!_options.Inplace || _options.MakeBackups || s.Sums[wantI].Offset >= offset ||
                         (s.Sums[wantI].Flags & SumflgSameOffset) != 0) &&
                        sum == s.Sums[wantI].Sum1 &&
                        Util.MemoryCompare(sum2, 0, s.Sums[wantI].Sum2, 0, s.S2Length) == 0)
                    {
                        i = wantI;
                    }
                    //set_want_i:
                    wantI = i + 1;

                    Matched(f, s, buf, offset, i, _sum);
                    offset += (int)(s.Sums[i].Len - 1);
                    k       = (UInt32)Math.Min(s.BLength, len - offset);
                    off     = buf.MapPtr(offset, (int)k);
                    sum     = CheckSum.GetChecksum1(map, off, (int)k);
                    s1      = sum & 0xFFFF;
                    s2      = sum >> 16;
                    _matches++;
                    break;
                } while (++j < s.Count && _targets[j].T == t);
null_tag:
                backup = offset - _lastMatch;
                if (backup < 0)
                {
                    backup = 0;
                }

                more = (offset + k) < len ? 1 : 0;
                off  = buf.MapPtr(offset - backup, (int)(k + more + backup)) + backup;
                s1  -= (UInt32)(CheckSum.ToInt(map[off]) + CheckSum.CharOffset);
                s2  -= (UInt32)(k * CheckSum.ToInt(map[off]) + CheckSum.CharOffset);
                off  = (k + off >= map.Length) ? (int)(map.Length - k - 1) : off;
                if (more != 0)
                {
                    s1 += (UInt32)(CheckSum.ToInt(map[k + off]) + CheckSum.CharOffset);
                    s2 += s1;
                }
                else
                {
                    --k;
                }

                if (backup >= ChunkSize + s.BLength && end - offset > ChunkSize)
                {
                    Matched(f, s, buf, (int)(offset - s.BLength), -2, _sum);
                }
            } while (++offset < end);

            Matched(f, s, buf, len, -1, _sum);
            buf.MapPtr(len - 1, 1);
        }
Example #17
0
        public void MatchSums(IoStream f, SumStruct s, MapFile buf, int len)
        {
            var fileSum = new byte[CheckSum.Md4SumLength];

            _lastMatch    = 0;
            _falseAlarms  = 0;
            _tagHits      = 0;
            _matches      = 0;
            _dataTransfer = 0;

            var sum = new Sum(_options);

            sum.Init(_options.ChecksumSeed);

            if (len > 0 && s.Count > 0)
            {
                BuildHashTable(s);

                if (_options.Verbose > 2)
                {
                    Log.WriteLine("built hash table");
                }

                HashSearch(f, s, buf, len, sum);

                if (_options.Verbose > 2)
                {
                    Log.WriteLine("done hash search");
                }
            }
            else
            {
                for (var j = 0; j < len - ChunkSize; j += ChunkSize)
                {
                    var n1 = Math.Min(ChunkSize, (len - ChunkSize) - j);
                    Matched(f, s, buf, j + n1, -2, sum);
                }
                Matched(f, s, buf, len, -1, sum);
            }

            fileSum = sum.End();
            if (buf != null && buf.Status)
            {
                fileSum[0]++;
            }

            if (_options.Verbose > 2)
            {
                Log.WriteLine("sending fileSum");
            }
            f.Write(fileSum, 0, CheckSum.Md4SumLength);

            _targets.Clear();

            if (_options.Verbose > 2)
            {
                Log.WriteLine("falseAlarms=" + _falseAlarms + " tagHits=" + _tagHits + " matches=" + _matches);
            }

            _totalTagHits             += _tagHits;
            _totalFalseAlarms         += _falseAlarms;
            _totalMatches             += _matches;
            Options.Stats.LiteralData += _dataTransfer;
        }
Example #18
0
 public void SendDeflatedToken(IoStream f, int token, MapFile buf, int offset, int nb, int toklen)
 {
 }
Example #19
0
 public int ReceiveDeflatedToken(IoStream f, byte[] data, int offset)
 {
     return(0);
 }
Example #20
0
        public void SendFileEntry(FileStruct file, IoStream ioStream, UInt32 baseflags)
        {
            var flags = baseflags;
            int l1 = 0, l2 = 0;

            if (ioStream == null)
            {
                return;
            }
            if (file == null)
            {
                ioStream.WriteByte(0);
                _lastName = String.Empty;
                return;
            }
            var fileName = file.GetFullName().Replace(":", String.Empty);

            for (l1 = 0;
                 _lastName.Length > l1 && (fileName[l1] == _lastName[l1]) && (l1 < 255);
                 l1++)
            {
            }
            l2 = fileName.Substring(l1).Length;

            flags |= Options.XmitSameName;

            if (l2 > 255)
            {
                flags |= Options.XmitLongName;
            }
            if (_options.ProtocolVersion >= 28)
            {
                if (flags == 0 && !Util.S_ISDIR(file.Mode))
                {
                    flags |= Options.XmitTopDir;
                }

                /*if ((flags & 0xFF00) > 0 || flags == 0)
                 * {
                 *  flags |= Options.XMIT_EXTENDED_FLAGS;
                 *  f.writeByte((byte)flags);
                 *  f.writeByte((byte)(flags >> 8));
                 * }
                 * else					*/
                ioStream.WriteByte((byte)flags);
            }
            else
            {
                if ((flags & 0xFF) == 0 && !Util.S_ISDIR(file.Mode))
                {
                    flags |= Options.XmitTopDir;
                }
                if ((flags & 0xFF) == 0)
                {
                    flags |= Options.XmitLongName;
                }
                ioStream.WriteByte((byte)flags);
            }
            if ((flags & Options.XmitSameName) != 0)
            {
                ioStream.WriteByte((byte)l1);
            }
            if ((flags & Options.XmitLongName) != 0)
            {
                ioStream.WriteInt(l2);
            }
            else
            {
                ioStream.WriteByte((byte)l2);
            }


            var b = Encoding.ASCII.GetBytes(fileName);

            ioStream.Write(b, l1, l2);
            ioStream.WriteLongInt(file.Length);


            if ((flags & Options.XmitSameTime) == 0)
            {
                ioStream.WriteInt(file.ModTime.Second);
            }
            if ((flags & Options.XmitSameMode) == 0)
            {
                ioStream.WriteInt((int)file.Mode);
            }
            if (_options.PreserveUid && (flags & Options.XmitSameUid) == 0)
            {
                ioStream.WriteInt(file.Uid);
            }
            if (_options.PreserveGid && (flags & Options.XmitSameGid) == 0)
            {
                ioStream.WriteInt(file.Gid);
            }
            if (_options.AlwaysChecksum)
            {
                byte[] sum;
                if (!Util.S_ISDIR(file.Mode))
                {
                    sum = file.Sum;
                }
                else if (_options.ProtocolVersion < 28)
                {
                    sum = new byte[16];
                }
                else
                {
                    sum = null;
                }

                if (sum != null)
                {
                    ioStream.Write(sum, 0, _options.ProtocolVersion < 21 ? 2 : CheckSum.Md4SumLength);
                }
            }

            _lastName = fileName;
        }
Example #21
0
 /// <summary>
 /// Do nothing
 /// </summary>
 /// <param name="f"></param>
 public static void SendListing(IoStream f) //@todo_long empty method
 {
 }
Example #22
0
        public List <FileStruct> SendFileList(ClientInfo clientInfo, string[] argv)
        {
            IoStream ioStream = null;

            if (clientInfo != null)
            {
                ioStream = clientInfo.IoStream;
            }

            string dir, oldDir;
            var    lastPath = String.Empty; //@todo_long seems to be Empty all the time
            var    fileName = String.Empty;
            var    useFffd  = false;        //@todo_long seems to be false all the time

            if (ShowFileListProgress() && ioStream != null)
            {
                StartFileListProgress("building file list");
            }
            var startWrite = Options.Stats.TotalWritten;
            var fileList   = new List <FileStruct>();

            if (ioStream != null)
            {
                ioStream.IoStartBufferingOut();
                if (Options.FilesFromFd != null) //@todo_long seems to be unused because filesFromFD seems to be null all the time
                {
                    if (!string.IsNullOrEmpty(argv[0]) && !Util.PushDir(argv[0]))
                    {
                        WinRsync.Exit("pushDir " + Util.FullFileName(argv[0]) + " failed", clientInfo);
                    }
                    useFffd = true;
                }
            }
            while (true)
            {
                if (useFffd) //@todo_long seems to be unused because useFFFD seems to be false all the time
                {
                    if ((fileName = ioStream.ReadFilesFromLine(Options.FilesFromFd, _options)).Length == 0)
                    {
                        break;
                    }
                }
                else
                {
                    if (argv.Length == 0)
                    {
                        break;
                    }
                    fileName = argv[0];
                    argv     = Util.DeleteFirstElement(argv);
                    if (fileName != null && fileName.Equals("."))
                    {
                        continue;
                    }
                    if (fileName != null)
                    {
                        fileName = fileName.Replace(@"\", "/");
                    }
                }
                // TODO: path length
                if (Directory.Exists(fileName) && !_options.Recurse && _options.FilesFrom == null)
                {
                    Log.WriteLine("skipping directory " + fileName);
                    continue;
                }

                dir    = null;
                oldDir = String.Empty;

                if (!_options.RelativePaths)
                {
                    var index = fileName.LastIndexOf('/');
                    if (index != -1)
                    {
                        if (index == 0)
                        {
                            dir = "/";
                        }
                        else
                        {
                            dir = fileName.Substring(0, index);
                        }
                        fileName = fileName.Substring(index + 1);
                    }
                }
                else
                {
                    if (ioStream != null && _options.ImpliedDirs && fileName.LastIndexOf('/') > 0)
                    {
                        var fileDir = fileName.Substring(0, fileName.LastIndexOf('/'));
                        var slash   = fileName;
                        var i       = 0;                                                               //@todo_long seems to be 0 all the time
                        while (i < fileDir.Length && i < lastPath.Length && fileDir[i] == lastPath[i]) //@todo_long seems that it is never executed because lastPath is allways Empty
                        {
                            if (fileDir[i] == '/')
                            {
                                slash = fileName.Substring(i);
                            }
                            i++;
                        }
                        if (i != fileName.LastIndexOf('/') || (i < lastPath.Length && lastPath[i] != '/'))//@todo_long seems to be executed unconditionally because i=0 and fileName.LastIndexOf('/') > 0
                        {
                            var copyLinksSaved = _options.CopyLinks;
                            var recurseSaved   = _options.Recurse;
                            _options.CopyLinks = _options.CopyUnsafeLinks;
                            _options.Recurse   = true;
                            int j;
                            while ((j = slash.IndexOf('/')) != -1)
                            {
                                SendFileName(ioStream, fileList, fileName.Substring(0, j), false, 0);
                                slash = slash.Substring(0, j) + ' ' + slash.Substring(j + 1);
                            }
                            _options.CopyLinks = copyLinksSaved;
                            _options.Recurse   = recurseSaved;
                            lastPath           = fileName.Substring(0, i);
                        }
                    }
                }
                if (!string.IsNullOrEmpty(dir))
                {
                    oldDir = Util.CurrDir;
                    if (!Util.PushDir(dir))
                    {
                        Log.WriteLine("pushDir " + Util.FullFileName(dir) + " failed");
                        continue;
                    }
                    if (_lastDir != null && _lastDir.Equals(dir))
                    {
                        _fileListDir = _lastDir;
                    }
                    else
                    {
                        _fileListDir = _lastDir = dir;
                    }
                }
                SendFileName(ioStream, fileList, fileName, _options.Recurse, Options.XmitTopDir);
                if (!string.IsNullOrEmpty(oldDir))
                {
                    _fileListDir = null;
                    if (Util.PopDir(oldDir))
                    {
                        WinRsync.Exit("pop_dir " + Util.FullFileName(dir) + " failed", clientInfo);
                    }
                }
            }
            if (ioStream != null)
            {
                SendFileEntry(null, ioStream, 0);
                if (ShowFileListProgress())
                {
                    FinishFileListProgress(fileList);
                }
            }
            CleanFileList(fileList, false, false);
            if (ioStream != null)
            {
                ioStream.WriteInt(0);
                Options.Stats.FileListSize = (int)(Options.Stats.TotalWritten - startWrite);
                Options.Stats.NumFiles     = fileList.Count;
            }

            if (_options.Verbose > 3)
            {
                OutputFileList(fileList);
            }
            if (_options.Verbose > 2)
            {
                Log.WriteLine("sendFileList done");
            }
            return(fileList);
        }