|
| 1 | +# _emx_link.py |
| 2 | + |
| 3 | +# Written by Andrew I MacIntyre, December 2002. |
| 4 | + |
| 5 | +"""_emx_link.py is a simplistic emulation of the Unix link(2) library routine |
| 6 | +for creating so-called hard links. It is intended to be imported into |
| 7 | +the os module in place of the unimplemented (on OS/2) Posix link() |
| 8 | +function (os.link()). |
| 9 | +
|
| 10 | +We do this on OS/2 by implementing a file copy, with link(2) semantics:- |
| 11 | + - the target cannot already exist; |
| 12 | + - we hope that the actual file open (if successful) is actually |
| 13 | + atomic... |
| 14 | +
|
| 15 | +Limitations of this approach/implementation include:- |
| 16 | + - no support for correct link counts (EMX stat(target).st_nlink |
| 17 | + is always 1); |
| 18 | + - thread safety undefined; |
| 19 | + - default file permissions (r+w) used, can't be over-ridden; |
| 20 | + - implemented in Python so comparatively slow, especially for large |
| 21 | + source files; |
| 22 | + - need sufficient free disk space to store the copy. |
| 23 | +
|
| 24 | +Behaviour:- |
| 25 | + - any exception should propagate to the caller; |
| 26 | + - want target to be an exact copy of the source, so use binary mode; |
| 27 | + - returns None, same as os.link() which is implemented in posixmodule.c; |
| 28 | + - target removed in the event of a failure where possible; |
| 29 | + - given the motivation to write this emulation came from trying to |
| 30 | + support a Unix resource lock implementation, where minimal overhead |
| 31 | + during creation of the target is desirable and the files are small, |
| 32 | + we read a source block before attempting to create the target so that |
| 33 | + we're ready to immediately write some data into it. |
| 34 | +""" |
| 35 | + |
| 36 | +import os |
| 37 | +import errno |
| 38 | + |
| 39 | +__all__ = ['link'] |
| 40 | + |
| 41 | +def link(source, target): |
| 42 | + """link(source, target) -> None |
| 43 | +
|
| 44 | + Attempt to hard link the source file to the target file name. |
| 45 | + On OS/2, this creates a complete copy of the source file. |
| 46 | + """ |
| 47 | + |
| 48 | + s = os.open(source, os.O_RDONLY | os.O_BINARY) |
| 49 | + if os.isatty(s): |
| 50 | + raise OSError, (errno.EXDEV, 'Cross-device link') |
| 51 | + data = os.read(s, 1024) |
| 52 | + |
| 53 | + try: |
| 54 | + t = os.open(target, os.O_WRONLY | os.O_BINARY | os.O_CREAT | os.O_EXCL) |
| 55 | + except OSError: |
| 56 | + os.close(s) |
| 57 | + raise |
| 58 | + |
| 59 | + try: |
| 60 | + while data: |
| 61 | + os.write(t, data) |
| 62 | + data = os.read(s, 1024) |
| 63 | + except OSError: |
| 64 | + os.close(s) |
| 65 | + os.close(t) |
| 66 | + os.unlink(target) |
| 67 | + raise |
| 68 | + |
| 69 | + os.close(s) |
| 70 | + os.close(t) |
| 71 | + |
| 72 | +if __name__ == '__main__': |
| 73 | + import sys |
| 74 | + try: |
| 75 | + link(sys.argv[1], sys.argv[2]) |
| 76 | + except IndexError: |
| 77 | + print 'Usage: emx_link <source> <target>' |
| 78 | + except OSError: |
| 79 | + print 'emx_link: %s' % str(sys.exc_info()[1]) |
0 commit comments