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