parser.add_argument('-k', '--requiredshares', help='the number of share files required to reconstruct (default 4)', default=4, type=int, metavar='K')
parser.add_argument('-f', '--force', help='overwrite any file which already in place an output file (share file)', action='store_true')
parser.add_argument('-v', '--verbose', help='print out messages about progress', action='store_true')
+ parser.add_argument('-q', '--quiet', help='quiet progress indications and warnings about silly choices of K and M', action='store_true')
parser.add_argument('-V', '--version', help='print out version number and exit', action='store_true')
args = parser.parse_args()
if args.prefix == "<stdin>":
args.prefix = ""
- if args.totalshares < 3:
- print "Invalid parameters, totalshares is required to be >= 3\nPlease see the accompanying documentation."
+ if args.verbose and args.quiet:
+ print "Please choose only one of --verbose and --quiet."
sys.exit(1)
- if args.totalshares > 256:
- print "Invalid parameters, totalshares is required to be <= 256\nPlease see the accompanying documentation."
+
+ if args.totalshares > 256 or args.totalshares < 1:
+ print "Invalid parameters, totalshares is required to be <= 256 and >= 1\nPlease see the accompanying documentation."
sys.exit(1)
- if args.requiredshares < 2:
- print "Invalid parameters, requiredshares is required to be >= 2\nPlease see the accompanying documentation."
- sys.exit(1)
- if args.requiredshares >= args.totalshares:
- print "Invalid parameters, requiredshares is required to be < totalshares\nPlease see the accompanying documentation."
+ if args.requiredshares > args.totalshares or args.requiredshares < 1:
+ print "Invalid parameters, requiredshares is required to be <= totalshares and >= 1\nPlease see the accompanying documentation."
sys.exit(1)
+ if not args.quiet:
+ if args.requiredshares == 1:
+ print "warning: silly parameters: requiredshares == 1, which means that every share will be a complete copy of the file. You could use \"cp\" for the same effect. But proceeding to do it anyway..."
+ if args.requiredshares == args.totalshares:
+ print "warning: silly parameters: requiredshares == totalshares, which means that all shares will be required in order to reconstruct the file. You could use \"split\" for the same effect. But proceeding to do it anyway..."
+
args.inputfile.seek(0, 2)
fsize = args.inputfile.tell()
args.inputfile.seek(0, 0)
def _build_header(m, k, pad, sh):
"""
- @param m: the total number of shares; 3 <= m <= 256
- @param k: the number of shares required to reconstruct; 2 <= k < m
+ @param m: the total number of shares; 1 <= m <= 256
+ @param k: the number of shares required to reconstruct; 1 <= k <= m
@param pad: the number of bytes of padding added to the file before encoding; 0 <= pad < k
@param sh: the shnum of this share; 0 <= k < m
@return: a string (which is hopefully short) encoding m, k, sh, and pad
"""
- assert m >= 3
+ assert m >= 1
assert m <= 2**8
- assert k >= 2
- assert k < m
+ assert k >= 1
+ assert k <= m
assert pad >= 0
assert pad < k
bitsused = 0
val = 0
- val |= (m - 3)
+ val |= (m - 1)
bitsused += 8 # the first 8 bits always encode m
- kbits = log_ceil(m-2, 2) # num bits needed to store all possible values of k
+ kbits = log_ceil(m, 2) # num bits needed to store all possible values of k
val <<= kbits
bitsused += kbits
- val |= (k - 2)
+ val |= (k - 1)
padbits = log_ceil(k, 2) # num bits needed to store all possible values of pad
val <<= padbits
val |= sh
- assert bitsused >= 11
- assert bitsused <= 32
+ assert bitsused >= 8, bitsused
+ assert bitsused <= 32, bitsused
if bitsused <= 16:
val <<= (16-bitsused)
if not ch:
raise CorruptedShareFilesError("Share files were corrupted -- share file %r didn't have a complete metadata header at the front. Perhaps the file was truncated." % (inf.name,))
byte = ord(ch)
- m = byte + 3
+ m = byte + 1
# The next few bits encode k.
- kbits = log_ceil(m-2, 2) # num bits needed to store all possible values of k
+ kbits = log_ceil(m, 2) # num bits needed to store all possible values of k
b2_bits_left = 8-kbits
kbitmask = MASK(kbits) << b2_bits_left
ch = inf.read(1)
if not ch:
raise CorruptedShareFilesError("Share files were corrupted -- share file %r didn't have a complete metadata header at the front. Perhaps the file was truncated." % (inf.name,))
byte = ord(ch)
- k = ((byte & kbitmask) >> b2_bits_left) + 2
+ k = ((byte & kbitmask) >> b2_bits_left) + 1
shbits = log_ceil(m, 2) # num bits needed to store all possible values of shnum
padbits = log_ceil(k, 2) # num bits needed to store all possible values of pad
class FileFec(unittest.TestCase):
def test_filefec_header(self):
- for m in [3, 5, 7, 9, 11, 17, 19, 33, 35, 65, 66, 67, 129, 130, 131, 254, 255, 256,]:
- for k in [2, 3, 5, 9, 17, 33, 65, 129, 255,]:
+ for m in [1, 2, 3, 5, 7, 9, 11, 17, 19, 33, 35, 65, 66, 67, 129, 130, 131, 254, 255, 256,]:
+ for k in [1, 2, 3, 5, 9, 17, 33, 65, 129, 255, 256,]:
if k >= m:
continue
for pad in [0, 1, k-1,]: