├── .gitignore
├── LICENSE
├── README.rst
├── fcp.nim
├── fcp.nim.cfg
└── fcp.nimble
/.gitignore:
--------------------------------------------------------------------------------
1 | fcp
2 | fcp.exe
3 | nimcache/
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Ryan Gonzalez
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | fcp
2 | ===
3 |
4 | An ultra-fast, multi-threaded file-copy utility written in `Nim `_. fcp excels in moving directories with a large number of moderately-sized or large files.
5 |
6 | Building
7 | ********
8 |
9 | If you have `Nimble `_ installed::
10 |
11 | $ nimble install
12 |
13 | Otherwise::
14 |
15 | $ nim c fcp
16 |
17 | Usage
18 | *****
19 |
20 | ::
21 |
22 | fcp []
23 |
24 | TODO
25 | ****
26 |
27 | - Test on Windows.
28 |
--------------------------------------------------------------------------------
/fcp.nim:
--------------------------------------------------------------------------------
1 | import os, threadpool, strutils
2 |
3 | type
4 | FilePath = object of RootObj
5 | src, dst: string
6 | FileList = seq[FilePath]
7 |
8 | var
9 | live = 0
10 | copied = 0
11 | threadMax = 20
12 |
13 | when declared(atomicAddFetch):
14 | template ainc(a: int) = discard atomicAddFetch(addr(a), 1, ATOMIC_RELAXED)
15 | template adec(a: int) = discard atomicAddFetch(addr(a), -1, ATOMIC_RELAXED)
16 | else:
17 | template ainc(a: int) = discard addAndFetch(addr(a), 1)
18 | template adec(a: int) = discard addAndFetch(addr(a), -1)
19 |
20 | proc `$$`[T](s: T, z: T): string = align($s, len($z), '0')
21 |
22 | proc copy(file: FilePath) {.thread.} =
23 | copyFileWithPermissions file.src, file.dst
24 | ainc copied
25 | adec live
26 |
27 | proc copyFiles(files: FileList) =
28 | var total = files.len
29 |
30 | template report() =
31 | stdout.flushFile
32 | stdout.write "\rFiles copied: $#, files left: $#, active threads: $#" % [
33 | copied $$ total,
34 | (total-copied) $$ total,
35 | live $$ threadMax
36 | ]
37 | stdout.flushFile
38 |
39 | for file in files:
40 | while live+1 > threadMax:
41 | stdout.flushFile
42 | ainc live
43 | spawn copy(file)
44 | report()
45 | while total-copied != 0: report()
46 | report()
47 | sync()
48 | report()
49 | echo()
50 |
51 | proc setupThreadCount(threads: string) =
52 | threadMax = threads.parseInt
53 | if threadMax <= 0:
54 | quit "Cannot have 0 or less threads"
55 |
56 | proc setupFileList(src, dst: string): seq[FilePath] =
57 | result = @[]
58 | if not existsDir src:
59 | quit "Source either doesn't exist or isn't a directory"
60 |
61 | if existsFile dst:
62 | quit "Destination is a file"
63 |
64 | createDir dst
65 |
66 | echo "Building directory list..."
67 |
68 | for path in walkDirRec src:
69 | var
70 | dstfile = dst / path[src.len .. ^1]
71 | parent = dstfile.parentDir
72 | if parent != "": createDir parent
73 | result.add FilePath(src: path, dst: dstfile)
74 |
75 | proc main() =
76 | var
77 | src, dst: string
78 | args: seq[string] = commandLineParams()
79 |
80 | if args.len != 2 and args.len != 3:
81 | quit "usage: fcp [=$#]" % [$threadMax]
82 |
83 | src = args[0]
84 | dst = args[1]
85 |
86 | if args.len == 3: setupThreadCount args[2]
87 |
88 | copyFiles setupFileList(src, dst)
89 |
90 | when isMainModule: main()
91 |
--------------------------------------------------------------------------------
/fcp.nim.cfg:
--------------------------------------------------------------------------------
1 | threads:on
2 | -d:release
3 |
--------------------------------------------------------------------------------
/fcp.nimble:
--------------------------------------------------------------------------------
1 | [Package]
2 | name = "fcp"
3 | version = "0.1.0"
4 | author = "Ryan Gonzalez"
5 | description = "A fast, multi-threaded file copy utility"
6 | license = "MIT"
7 | bin = "fcp"
8 | InstallFiles = """
9 | fcp.nim
10 | fcp.nim.cfg
11 | """
12 |
13 | [Deps]
14 | requires = "nim >= 0.10.3"
15 |
--------------------------------------------------------------------------------