Subversion Repositories Programming Utils

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
86 rm5248 1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements.  See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership.  The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License.  You may obtain a copy of the License at
9
 *
10
 *  http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
 
20
package org.apache.sshd.common.file.nativefs;
21
 
22
import java.io.File;
23
import java.io.FileOutputStream;
24
import java.io.IOException;
25
import java.io.OutputStream;
26
import java.nio.ByteBuffer;
27
import java.nio.channels.FileChannel;
28
import java.nio.channels.SeekableByteChannel;
29
import java.nio.file.Files;
30
import java.nio.file.LinkOption;
31
import java.nio.file.Path;
32
import java.nio.file.Paths;
33
import java.nio.file.StandardOpenOption;
34
import java.nio.file.attribute.FileTime;
35
import java.nio.file.attribute.GroupPrincipal;
36
import java.nio.file.attribute.PosixFilePermission;
37
import java.nio.file.attribute.UserPrincipal;
38
import java.nio.file.attribute.UserPrincipalLookupService;
39
import java.util.EnumSet;
40
import java.util.HashMap;
41
import java.util.HashSet;
42
import java.util.Map;
43
import java.util.Set;
44
 
45
import org.apache.sshd.common.file.SshFile;
46
 
47
/**
48
 * <strong>Internal class, do not use directly.</strong>
49
 *
50
 * This class wraps native file object.
51
 *
52
 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
53
 */
54
public class NativeSshFileNio extends NativeSshFile {
55
 
56
    /**
57
     * Constructor, internal do not use directly.
58
     * @param nativeFileSystemView
59
     */
60
    public NativeSshFileNio(NativeFileSystemView nativeFileSystemView, String fileName, File file, String userName) {
61
        super(nativeFileSystemView, fileName, file, userName);
62
    }
63
 
64
    public Map<Attribute, Object> getAttributes(boolean followLinks) throws IOException {
65
        String[] attrs = new String[] { "unix:*", "posix:*", "*" };
66
        Map<String, Object> a = null;
67
        for (String attr : attrs) {
68
            try {
69
                a = Files.readAttributes(
70
                        file.toPath(), attr,
71
                        followLinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS});
72
                break;
73
            } catch (UnsupportedOperationException e) {
74
                // Ignore
75
            }
76
        }
77
        if (a == null) {
78
            throw new IllegalStateException();
79
        }
80
        Map<Attribute, Object> map = new HashMap<Attribute, Object>();
81
        map.put(Attribute.Size, a.get("size"));
82
        if (a.containsKey("uid")) {
83
            map.put(Attribute.Uid, a.get("uid"));
84
        }
85
        if (a.containsKey("owner")) {
86
            map.put(Attribute.Owner, ((UserPrincipal) a.get("owner")).getName());
87
        } else {
88
            map.put(Attribute.Owner, userName);
89
        }
90
        if (a.containsKey("gid")) {
91
            map.put(Attribute.Gid, a.get("gid"));
92
        }
93
        if (a.containsKey("group")) {
94
            map.put(Attribute.Group, ((GroupPrincipal) a.get("group")).getName());
95
        } else {
96
            map.put(Attribute.Group, userName);
97
        }
98
        map.put(Attribute.IsDirectory, a.get("isDirectory"));
99
        map.put(Attribute.IsRegularFile, a.get("isRegularFile"));
100
        map.put(Attribute.IsSymbolicLink, a.get("isSymbolicLink"));
101
        map.put(Attribute.CreationTime, ((FileTime) a.get("creationTime")).toMillis());
102
        map.put(Attribute.LastModifiedTime, ((FileTime) a.get("lastModifiedTime")).toMillis());
103
        map.put(Attribute.LastAccessTime, ((FileTime) a.get("lastAccessTime")).toMillis());
104
        if (a.containsKey("permissions")) {
105
            map.put(Attribute.Permissions, fromPerms((Set<PosixFilePermission>) a.get("permissions")));
106
        } else {
107
            EnumSet<Permission> p = EnumSet.noneOf(Permission.class);
108
            if (isReadable()) {
109
                p.add(Permission.UserRead);
110
                p.add(Permission.GroupRead);
111
                p.add(Permission.OthersRead);
112
            }
113
            if (isWritable()) {
114
                p.add(Permission.UserWrite);
115
                p.add(Permission.GroupWrite);
116
                p.add(Permission.OthersWrite);
117
            }
118
            if (isExecutable()) {
119
                p.add(Permission.UserExecute);
120
                p.add(Permission.GroupExecute);
121
                p.add(Permission.OthersExecute);
122
            }
123
            map.put(Attribute.Permissions, p);
124
        }
125
        return map;
126
    }
127
 
128
    public void setAttributes(Map<Attribute, Object> attributes) throws IOException {
129
        Set<Attribute> unsupported = new HashSet<Attribute>();
130
        for (Attribute attribute : attributes.keySet()) {
131
            String name = null;
132
            Object value = attributes.get(attribute);
133
            switch (attribute) {
134
                case Size:             {
135
                    long newSize = (Long) value;
136
                    FileChannel outChan = new FileOutputStream(file, true).getChannel();
137
                    outChan.truncate(newSize);
138
                    outChan.close();
139
                    continue;
140
                }
141
                case Uid:              name = "unix:uid"; break;
142
                case Gid:              name = "unix:gid"; break;
143
                case Owner:            name = "posix:owner"; value = toUser((String) value); break;
144
                case Group:            name = "posix:group"; value = toGroup((String) value); break;
145
                case Permissions:      name = "posix:permissions"; value = toPerms((EnumSet<Permission>) value); break;
146
                case CreationTime:     name = "basic:creationTime"; value = FileTime.fromMillis((Long) value); break;
147
                case LastModifiedTime: name = "basic:lastModifiedTime"; value = FileTime.fromMillis((Long) value); break;
148
                case LastAccessTime:   name = "basic:lastAccessTime"; value = FileTime.fromMillis((Long) value); break;
149
            }
150
            if (name != null && value != null) {
151
                try {
152
                    Files.setAttribute(file.toPath(), name, value, LinkOption.NOFOLLOW_LINKS);
153
                } catch (UnsupportedOperationException e) {
154
                    unsupported.add(attribute);
155
                }
156
            }
157
        }
158
        handleUnsupportedAttributes(unsupported);
159
    }
160
 
161
    public String readSymbolicLink() throws IOException {
162
        Path path = file.toPath();
163
        Path link = Files.readSymbolicLink(path);
164
        return link.toString();
165
    }
166
 
167
    public void createSymbolicLink(SshFile destination) throws IOException {
168
        Path link = file.toPath();
169
        Path target = Paths.get(destination.getAbsolutePath());
170
        Files.createSymbolicLink(target, link);
171
    }
172
 
173
    private EnumSet<Permission> fromPerms(Set<PosixFilePermission> perms) {
174
        EnumSet<Permission> p = EnumSet.noneOf(Permission.class);
175
        for (PosixFilePermission perm : perms) {
176
            switch (perm) {
177
                case OWNER_READ:     p.add(Permission.UserRead); break;
178
                case OWNER_WRITE:    p.add(Permission.UserWrite); break;
179
                case OWNER_EXECUTE:  p.add(Permission.UserExecute); break;
180
                case GROUP_READ:     p.add(Permission.GroupRead); break;
181
                case GROUP_WRITE:    p.add(Permission.GroupWrite); break;
182
                case GROUP_EXECUTE:  p.add(Permission.GroupExecute); break;
183
                case OTHERS_READ:    p.add(Permission.OthersRead); break;
184
                case OTHERS_WRITE:   p.add(Permission.OthersWrite); break;
185
                case OTHERS_EXECUTE: p.add(Permission.OthersExecute); break;
186
            }
187
        }
188
        return p;
189
    }
190
 
191
    private GroupPrincipal toGroup(String name) throws IOException {
192
        UserPrincipalLookupService lookupService = file.toPath().getFileSystem().getUserPrincipalLookupService();
193
        return lookupService.lookupPrincipalByGroupName(name);
194
    }
195
 
196
    private UserPrincipal toUser(String name) throws IOException {
197
        UserPrincipalLookupService lookupService = file.toPath().getFileSystem().getUserPrincipalLookupService();
198
        return lookupService.lookupPrincipalByName(name);
199
    }
200
 
201
    private Set<PosixFilePermission> toPerms(EnumSet<Permission> perms) {
202
        Set<PosixFilePermission> set = new HashSet<PosixFilePermission>();
203
        for (Permission p : perms) {
204
            switch (p) {
205
                case UserRead:      set.add(PosixFilePermission.OWNER_READ); break;
206
                case UserWrite:     set.add(PosixFilePermission.OWNER_WRITE); break;
207
                case UserExecute:   set.add(PosixFilePermission.OWNER_EXECUTE); break;
208
                case GroupRead:     set.add(PosixFilePermission.GROUP_READ); break;
209
                case GroupWrite:    set.add(PosixFilePermission.GROUP_WRITE); break;
210
                case GroupExecute:  set.add(PosixFilePermission.GROUP_EXECUTE); break;
211
                case OthersRead:    set.add(PosixFilePermission.OTHERS_READ); break;
212
                case OthersWrite:   set.add(PosixFilePermission.OTHERS_WRITE); break;
213
                case OthersExecute: set.add(PosixFilePermission.OTHERS_EXECUTE); break;
214
            }
215
        }
216
        return set;
217
    }
218
 
219
    @Override
220
    public OutputStream createOutputStream(long offset) throws IOException {
221
        Path path = file.toPath();
222
        final SeekableByteChannel sbc = Files.newByteChannel(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
223
        if (offset > 0) {
224
            sbc.position(offset);
225
        }
226
        return new OutputStream() {
227
            @Override
228
            public void write(int b) throws IOException {
229
                write(new byte[] { (byte) b }, 0, 1);
230
            }
231
 
232
            @Override
233
            public void write(byte[] b, int off, int len) throws IOException {
234
                if (b == null) {
235
                    throw new NullPointerException();
236
                } else if ((off < 0) || (off > b.length) || (len < 0) ||
237
                        ((off + len) > b.length) || ((off + len) < 0)) {
238
                    throw new IndexOutOfBoundsException();
239
                } else if (len == 0) {
240
                    return;
241
                }
242
                sbc.write(ByteBuffer.wrap(b, off, len));
243
            }
244
 
245
            @Override
246
            public void close() throws IOException {
247
                sbc.close();
248
            }
249
        };
250
    }
251
 
252
}