|
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]) |