View Javadoc
1   /*
2    * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com> and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.lfs.server.fs;
11  
12  import static org.eclipse.jgit.util.HttpSupport.HDR_AUTHORIZATION;
13  
14  import java.io.IOException;
15  import java.nio.channels.FileChannel;
16  import java.nio.channels.ReadableByteChannel;
17  import java.nio.file.Files;
18  import java.nio.file.Path;
19  import java.nio.file.StandardOpenOption;
20  import java.util.Collections;
21  
22  import org.eclipse.jgit.annotations.Nullable;
23  import org.eclipse.jgit.lfs.internal.AtomicObjectOutputStream;
24  import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
25  import org.eclipse.jgit.lfs.lib.Constants;
26  import org.eclipse.jgit.lfs.server.LargeFileRepository;
27  import org.eclipse.jgit.lfs.server.Response;
28  import org.eclipse.jgit.lfs.server.Response.Action;
29  
30  /**
31   * Repository storing large objects in the file system
32   *
33   * @since 4.3
34   */
35  public class FileLfsRepository implements LargeFileRepository {
36  
37  	private String url;
38  	private final Path dir;
39  
40  	/**
41  	 * <p>Constructor for FileLfsRepository.</p>
42  	 *
43  	 * @param url
44  	 *            external URL of this repository
45  	 * @param dir
46  	 *            storage directory
47  	 * @throws java.io.IOException
48  	 */
49  	public FileLfsRepository(String url, Path dir) throws IOException {
50  		this.url = url;
51  		this.dir = dir;
52  		Files.createDirectories(dir);
53  	}
54  
55  	/** {@inheritDoc} */
56  	@Override
57  	public Response.Action getDownloadAction(AnyLongObjectId id) {
58  		return getAction(id);
59  	}
60  
61  	/** {@inheritDoc} */
62  	@Override
63  	public Action getUploadAction(AnyLongObjectId id, long size) {
64  		return getAction(id);
65  	}
66  
67  	/** {@inheritDoc} */
68  	@Override
69  	@Nullable
70  	public Action getVerifyAction(AnyLongObjectId id) {
71  		return null;
72  	}
73  
74  	/** {@inheritDoc} */
75  	@Override
76  	public long getSize(AnyLongObjectId id) throws IOException {
77  		Path p = getPath(id);
78  		if (Files.exists(p)) {
79  			return Files.size(p);
80  		}
81  		return -1;
82  	}
83  
84  	/**
85  	 * Get the storage directory
86  	 *
87  	 * @return the path of the storage directory
88  	 */
89  	public Path getDir() {
90  		return dir;
91  	}
92  
93  	/**
94  	 * Get the path where the given object is stored
95  	 *
96  	 * @param id
97  	 *            id of a large object
98  	 * @return path the object's storage path
99  	 */
100 	protected Path getPath(AnyLongObjectId id) {
101 		StringBuilder s = new StringBuilder(
102 				Constants.LONG_OBJECT_ID_STRING_LENGTH + 6);
103 		s.append(toHexCharArray(id.getFirstByte())).append('/');
104 		s.append(toHexCharArray(id.getSecondByte())).append('/');
105 		s.append(id.name());
106 		return dir.resolve(s.toString());
107 	}
108 
109 	private Response.Action getAction(AnyLongObjectId id) {
110 		Response.Action a = new Response.Action();
111 		a.href = url + id.getName();
112 		a.header = Collections.singletonMap(HDR_AUTHORIZATION, "not:required"); //$NON-NLS-1$
113 		return a;
114 	}
115 
116 	ReadableByteChannel getReadChannel(AnyLongObjectId id)
117 			throws IOException {
118 		return FileChannel.open(getPath(id), StandardOpenOption.READ);
119 	}
120 
121 	AtomicObjectOutputStream getOutputStream(AnyLongObjectId id)
122 			throws IOException {
123 		Path path = getPath(id);
124 		Path parent = path.getParent();
125 		if (parent != null) {
126 			Files.createDirectories(parent);
127 		}
128 		return new AtomicObjectOutputStream(path, id);
129 	}
130 
131 	private static char[] toHexCharArray(int b) {
132 		final char[] dst = new char[2];
133 		formatHexChar(dst, 0, b);
134 		return dst;
135 	}
136 
137 	private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
138 			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
139 
140 	private static void formatHexChar(char[] dst, int p, int b) {
141 		int o = p + 1;
142 		while (o >= p && b != 0) {
143 			dst[o--] = hexchar[b & 0xf];
144 			b >>>= 4;
145 		}
146 		while (o >= p)
147 			dst[o--] = '0';
148 	}
149 
150 	/**
151 	 * @return the url of the content server
152 	 * @since 4.11
153 	 */
154 	public String getUrl() {
155 		return url;
156 	}
157 
158 	/**
159 	 * @param url
160 	 *            the url of the content server
161 	 * @since 4.11
162 	 */
163 	public void setUrl(String url) {
164 		this.url = url;
165 	}
166 }