1OPEN_BY_HANDLE_AT(2) Linux Programmer's Manual OPEN_BY_HANDLE_AT(2)
2
3
4
6 name_to_handle_at, open_by_handle_at - obtain handle for a pathname and
7 open file via a handle
8
10 #define _GNU_SOURCE /* See feature_test_macros(7) */
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14
15 int name_to_handle_at(int dirfd, const char *pathname,
16 struct file_handle *handle,
17 int *mount_id, int flags);
18
19 int open_by_handle_at(int mount_fd, struct file_handle *handle,
20 int flags);
21
23 The name_to_handle_at() and open_by_handle_at() system calls split the
24 functionality of openat(2) into two parts: name_to_handle_at() returns
25 an opaque handle that corresponds to a specified file; open_by_han‐
26 dle_at() opens the file corresponding to a handle returned by a previ‐
27 ous call to name_to_handle_at() and returns an open file descriptor.
28
29 name_to_handle_at()
30 The name_to_handle_at() system call returns a file handle and a mount
31 ID corresponding to the file specified by the dirfd and pathname argu‐
32 ments. The file handle is returned via the argument handle, which is a
33 pointer to a structure of the following form:
34
35 struct file_handle {
36 unsigned int handle_bytes; /* Size of f_handle [in, out] */
37 int handle_type; /* Handle type [out] */
38 unsigned char f_handle[0]; /* File identifier (sized by
39 caller) [out] */
40 };
41
42 It is the caller's responsibility to allocate the structure with a size
43 large enough to hold the handle returned in f_handle. Before the call,
44 the handle_bytes field should be initialized to contain the allocated
45 size for f_handle. (The constant MAX_HANDLE_SZ, defined in <fcntl.h>,
46 specifies the maximum expected size for a file handle. It is not a
47 guaranteed upper limit as future filesystems may require more space.)
48 Upon successful return, the handle_bytes field is updated to contain
49 the number of bytes actually written to f_handle.
50
51 The caller can discover the required size for the file_handle structure
52 by making a call in which handle->handle_bytes is zero; in this case,
53 the call fails with the error EOVERFLOW and handle->handle_bytes is set
54 to indicate the required size; the caller can then use this information
55 to allocate a structure of the correct size (see EXAMPLES below). Some
56 care is needed here as EOVERFLOW can also indicate that no file handle
57 is available for this particular name in a filesystem which does nor‐
58 mally support file-handle lookup. This case can be detected when the
59 EOVERFLOW error is returned without handle_bytes being increased.
60
61 Other than the use of the handle_bytes field, the caller should treat
62 the file_handle structure as an opaque data type: the handle_type and
63 f_handle fields are needed only by a subsequent call to open_by_han‐
64 dle_at().
65
66 The flags argument is a bit mask constructed by ORing together zero or
67 more of AT_EMPTY_PATH and AT_SYMLINK_FOLLOW, described below.
68
69 Together, the pathname and dirfd arguments identify the file for which
70 a handle is to be obtained. There are four distinct cases:
71
72 * If pathname is a nonempty string containing an absolute pathname,
73 then a handle is returned for the file referred to by that pathname.
74 In this case, dirfd is ignored.
75
76 * If pathname is a nonempty string containing a relative pathname and
77 dirfd has the special value AT_FDCWD, then pathname is interpreted
78 relative to the current working directory of the caller, and a han‐
79 dle is returned for the file to which it refers.
80
81 * If pathname is a nonempty string containing a relative pathname and
82 dirfd is a file descriptor referring to a directory, then pathname
83 is interpreted relative to the directory referred to by dirfd, and a
84 handle is returned for the file to which it refers. (See openat(2)
85 for an explanation of why "directory file descriptors" are useful.)
86
87 * If pathname is an empty string and flags specifies the value
88 AT_EMPTY_PATH, then dirfd can be an open file descriptor referring
89 to any type of file, or AT_FDCWD, meaning the current working direc‐
90 tory, and a handle is returned for the file to which it refers.
91
92 The mount_id argument returns an identifier for the filesystem mount
93 that corresponds to pathname. This corresponds to the first field in
94 one of the records in /proc/self/mountinfo. Opening the pathname in
95 the fifth field of that record yields a file descriptor for the mount
96 point; that file descriptor can be used in a subsequent call to
97 open_by_handle_at(). mount_id is returned both for a successful call
98 and for a call that results in the error EOVERFLOW.
99
100 By default, name_to_handle_at() does not dereference pathname if it is
101 a symbolic link, and thus returns a handle for the link itself. If
102 AT_SYMLINK_FOLLOW is specified in flags, pathname is dereferenced if it
103 is a symbolic link (so that the call returns a handle for the file re‐
104 ferred to by the link).
105
106 name_to_handle_at() does not trigger a mount when the final component
107 of the pathname is an automount point. When a filesystem supports both
108 file handles and automount points, a name_to_handle_at() call on an au‐
109 tomount point will return with error EOVERFLOW without having increased
110 handle_bytes. This can happen since Linux 4.13 with NFS when accessing
111 a directory which is on a separate filesystem on the server. In this
112 case, the automount can be triggered by adding a "/" to the end of the
113 pathname.
114
115 open_by_handle_at()
116 The open_by_handle_at() system call opens the file referred to by han‐
117 dle, a file handle returned by a previous call to name_to_handle_at().
118
119 The mount_fd argument is a file descriptor for any object (file, direc‐
120 tory, etc.) in the mounted filesystem with respect to which handle
121 should be interpreted. The special value AT_FDCWD can be specified,
122 meaning the current working directory of the caller.
123
124 The flags argument is as for open(2). If handle refers to a symbolic
125 link, the caller must specify the O_PATH flag, and the symbolic link is
126 not dereferenced; the O_NOFOLLOW flag, if specified, is ignored.
127
128 The caller must have the CAP_DAC_READ_SEARCH capability to invoke
129 open_by_handle_at().
130
132 On success, name_to_handle_at() returns 0, and open_by_handle_at() re‐
133 turns a file descriptor (a nonnegative integer).
134
135 In the event of an error, both system calls return -1 and set errno to
136 indicate the cause of the error.
137
139 name_to_handle_at() and open_by_handle_at() can fail for the same er‐
140 rors as openat(2). In addition, they can fail with the errors noted
141 below.
142
143 name_to_handle_at() can fail with the following errors:
144
145 EFAULT pathname, mount_id, or handle points outside your accessible ad‐
146 dress space.
147
148 EINVAL flags includes an invalid bit value.
149
150 EINVAL handle->handle_bytes is greater than MAX_HANDLE_SZ.
151
152 ENOENT pathname is an empty string, but AT_EMPTY_PATH was not specified
153 in flags.
154
155 ENOTDIR
156 The file descriptor supplied in dirfd does not refer to a direc‐
157 tory, and it is not the case that both flags includes
158 AT_EMPTY_PATH and pathname is an empty string.
159
160 EOPNOTSUPP
161 The filesystem does not support decoding of a pathname to a file
162 handle.
163
164 EOVERFLOW
165 The handle->handle_bytes value passed into the call was too
166 small. When this error occurs, handle->handle_bytes is updated
167 to indicate the required size for the handle.
168
169 open_by_handle_at() can fail with the following errors:
170
171 EBADF mount_fd is not an open file descriptor.
172
173 EFAULT handle points outside your accessible address space.
174
175 EINVAL handle->handle_bytes is greater than MAX_HANDLE_SZ or is equal
176 to zero.
177
178 ELOOP handle refers to a symbolic link, but O_PATH was not specified
179 in flags.
180
181 EPERM The caller does not have the CAP_DAC_READ_SEARCH capability.
182
183 ESTALE The specified handle is not valid. This error will occur if,
184 for example, the file has been deleted.
185
187 These system calls first appeared in Linux 2.6.39. Library support is
188 provided in glibc since version 2.14.
189
191 These system calls are nonstandard Linux extensions.
192
193 FreeBSD has a broadly similar pair of system calls in the form of
194 getfh() and openfh().
195
197 A file handle can be generated in one process using name_to_handle_at()
198 and later used in a different process that calls open_by_handle_at().
199
200 Some filesystem don't support the translation of pathnames to file han‐
201 dles, for example, /proc, /sys, and various network filesystems.
202
203 A file handle may become invalid ("stale") if a file is deleted, or for
204 other filesystem-specific reasons. Invalid handles are notified by an
205 ESTALE error from open_by_handle_at().
206
207 These system calls are designed for use by user-space file servers.
208 For example, a user-space NFS server might generate a file handle and
209 pass it to an NFS client. Later, when the client wants to open the
210 file, it could pass the handle back to the server. This sort of func‐
211 tionality allows a user-space file server to operate in a stateless
212 fashion with respect to the files it serves.
213
214 If pathname refers to a symbolic link and flags does not specify
215 AT_SYMLINK_FOLLOW, then name_to_handle_at() returns a handle for the
216 link (rather than the file to which it refers). The process receiving
217 the handle can later perform operations on the symbolic link by con‐
218 verting the handle to a file descriptor using open_by_handle_at() with
219 the O_PATH flag, and then passing the file descriptor as the dirfd ar‐
220 gument in system calls such as readlinkat(2) and fchownat(2).
221
222 Obtaining a persistent filesystem ID
223 The mount IDs in /proc/self/mountinfo can be reused as filesystems are
224 unmounted and mounted. Therefore, the mount ID returned by
225 name_to_handle_at() (in *mount_id) should not be treated as a persis‐
226 tent identifier for the corresponding mounted filesystem. However, an
227 application can use the information in the mountinfo record that corre‐
228 sponds to the mount ID to derive a persistent identifier.
229
230 For example, one can use the device name in the fifth field of the
231 mountinfo record to search for the corresponding device UUID via the
232 symbolic links in /dev/disks/by-uuid. (A more comfortable way of ob‐
233 taining the UUID is to use the libblkid(3) library.) That process can
234 then be reversed, using the UUID to look up the device name, and then
235 obtaining the corresponding mount point, in order to produce the
236 mount_fd argument used by open_by_handle_at().
237
239 The two programs below demonstrate the use of name_to_handle_at() and
240 open_by_handle_at(). The first program (t_name_to_handle_at.c) uses
241 name_to_handle_at() to obtain the file handle and mount ID for the file
242 specified in its command-line argument; the handle and mount ID are
243 written to standard output.
244
245 The second program (t_open_by_handle_at.c) reads a mount ID and file
246 handle from standard input. The program then employs open_by_han‐
247 dle_at() to open the file using that handle. If an optional command-
248 line argument is supplied, then the mount_fd argument for open_by_han‐
249 dle_at() is obtained by opening the directory named in that argument.
250 Otherwise, mount_fd is obtained by scanning /proc/self/mountinfo to
251 find a record whose mount ID matches the mount ID read from standard
252 input, and the mount directory specified in that record is opened.
253 (These programs do not deal with the fact that mount IDs are not per‐
254 sistent.)
255
256 The following shell session demonstrates the use of these two programs:
257
258 $ echo 'Can you please think about it?' > cecilia.txt
259 $ ./t_name_to_handle_at cecilia.txt > fh
260 $ ./t_open_by_handle_at < fh
261 open_by_handle_at: Operation not permitted
262 $ sudo ./t_open_by_handle_at < fh # Need CAP_SYS_ADMIN
263 Read 31 bytes
264 $ rm cecilia.txt
265
266 Now we delete and (quickly) re-create the file so that it has the same
267 content and (by chance) the same inode. Nevertheless, open_by_han‐
268 dle_at() recognizes that the original file referred to by the file han‐
269 dle no longer exists.
270
271 $ stat --printf="%i\n" cecilia.txt # Display inode number
272 4072121
273 $ rm cecilia.txt
274 $ echo 'Can you please think about it?' > cecilia.txt
275 $ stat --printf="%i\n" cecilia.txt # Check inode number
276 4072121
277 $ sudo ./t_open_by_handle_at < fh
278 open_by_handle_at: Stale NFS file handle
279
280 Program source: t_name_to_handle_at.c
281
282 #define _GNU_SOURCE
283 #include <sys/types.h>
284 #include <sys/stat.h>
285 #include <fcntl.h>
286 #include <stdio.h>
287 #include <stdlib.h>
288 #include <unistd.h>
289 #include <errno.h>
290 #include <string.h>
291
292 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
293 } while (0)
294
295 int
296 main(int argc, char *argv[])
297 {
298 struct file_handle *fhp;
299 int mount_id, fhsize, flags, dirfd;
300 char *pathname;
301
302 if (argc != 2) {
303 fprintf(stderr, "Usage: %s pathname\n", argv[0]);
304 exit(EXIT_FAILURE);
305 }
306
307 pathname = argv[1];
308
309 /* Allocate file_handle structure */
310
311 fhsize = sizeof(*fhp);
312 fhp = malloc(fhsize);
313 if (fhp == NULL)
314 errExit("malloc");
315
316 /* Make an initial call to name_to_handle_at() to discover
317 the size required for file handle */
318
319 dirfd = AT_FDCWD; /* For name_to_handle_at() calls */
320 flags = 0; /* For name_to_handle_at() calls */
321 fhp->handle_bytes = 0;
322 if (name_to_handle_at(dirfd, pathname, fhp,
323 &mount_id, flags) != -1 || errno != EOVERFLOW) {
324 fprintf(stderr, "Unexpected result from name_to_handle_at()\n");
325 exit(EXIT_FAILURE);
326 }
327
328 /* Reallocate file_handle structure with correct size */
329
330 fhsize = sizeof(*fhp) + fhp->handle_bytes;
331 fhp = realloc(fhp, fhsize); /* Copies fhp->handle_bytes */
332 if (fhp == NULL)
333 errExit("realloc");
334
335 /* Get file handle from pathname supplied on command line */
336
337 if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == -1)
338 errExit("name_to_handle_at");
339
340 /* Write mount ID, file handle size, and file handle to stdout,
341 for later reuse by t_open_by_handle_at.c */
342
343 printf("%d\n", mount_id);
344 printf("%u %d ", fhp->handle_bytes, fhp->handle_type);
345 for (int j = 0; j < fhp->handle_bytes; j++)
346 printf(" %02x", fhp->f_handle[j]);
347 printf("\n");
348
349 exit(EXIT_SUCCESS);
350 }
351
352 Program source: t_open_by_handle_at.c
353
354 #define _GNU_SOURCE
355 #include <sys/types.h>
356 #include <sys/stat.h>
357 #include <fcntl.h>
358 #include <limits.h>
359 #include <stdio.h>
360 #include <stdlib.h>
361 #include <unistd.h>
362 #include <string.h>
363
364 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
365 } while (0)
366
367 /* Scan /proc/self/mountinfo to find the line whose mount ID matches
368 'mount_id'. (An easier way to do this is to install and use the
369 'libmount' library provided by the 'util-linux' project.)
370 Open the corresponding mount path and return the resulting file
371 descriptor. */
372
373 static int
374 open_mount_path_by_id(int mount_id)
375 {
376 char *linep;
377 size_t lsize;
378 char mount_path[PATH_MAX];
379 int mi_mount_id, found;
380 ssize_t nread;
381 FILE *fp;
382
383 fp = fopen("/proc/self/mountinfo", "r");
384 if (fp == NULL)
385 errExit("fopen");
386
387 found = 0;
388 linep = NULL;
389 while (!found) {
390 nread = getline(&linep, &lsize, fp);
391 if (nread == -1)
392 break;
393
394 nread = sscanf(linep, "%d %*d %*s %*s %s",
395 &mi_mount_id, mount_path);
396 if (nread != 2) {
397 fprintf(stderr, "Bad sscanf()\n");
398 exit(EXIT_FAILURE);
399 }
400
401 if (mi_mount_id == mount_id)
402 found = 1;
403 }
404 free(linep);
405
406 fclose(fp);
407
408 if (!found) {
409 fprintf(stderr, "Could not find mount point\n");
410 exit(EXIT_FAILURE);
411 }
412
413 return open(mount_path, O_RDONLY);
414 }
415
416 int
417 main(int argc, char *argv[])
418 {
419 struct file_handle *fhp;
420 int mount_id, fd, mount_fd, handle_bytes;
421 ssize_t nread;
422 char buf[1000];
423 #define LINE_SIZE 100
424 char line1[LINE_SIZE], line2[LINE_SIZE];
425 char *nextp;
426
427 if ((argc > 1 && strcmp(argv[1], "--help") == 0) || argc > 2) {
428 fprintf(stderr, "Usage: %s [mount-path]\n", argv[0]);
429 exit(EXIT_FAILURE);
430 }
431
432 /* Standard input contains mount ID and file handle information:
433
434 Line 1: <mount_id>
435 Line 2: <handle_bytes> <handle_type> <bytes of handle in hex>
436 */
437
438 if ((fgets(line1, sizeof(line1), stdin) == NULL) ||
439 (fgets(line2, sizeof(line2), stdin) == NULL)) {
440 fprintf(stderr, "Missing mount_id / file handle\n");
441 exit(EXIT_FAILURE);
442 }
443
444 mount_id = atoi(line1);
445
446 handle_bytes = strtoul(line2, &nextp, 0);
447
448 /* Given handle_bytes, we can now allocate file_handle structure */
449
450 fhp = malloc(sizeof(*fhp) + handle_bytes);
451 if (fhp == NULL)
452 errExit("malloc");
453
454 fhp->handle_bytes = handle_bytes;
455
456 fhp->handle_type = strtoul(nextp, &nextp, 0);
457
458 for (int j = 0; j < fhp->handle_bytes; j++)
459 fhp->f_handle[j] = strtoul(nextp, &nextp, 16);
460
461 /* Obtain file descriptor for mount point, either by opening
462 the pathname specified on the command line, or by scanning
463 /proc/self/mounts to find a mount that matches the 'mount_id'
464 that we received from stdin. */
465
466 if (argc > 1)
467 mount_fd = open(argv[1], O_RDONLY);
468 else
469 mount_fd = open_mount_path_by_id(mount_id);
470
471 if (mount_fd == -1)
472 errExit("opening mount fd");
473
474 /* Open file using handle and mount point */
475
476 fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);
477 if (fd == -1)
478 errExit("open_by_handle_at");
479
480 /* Try reading a few bytes from the file */
481
482 nread = read(fd, buf, sizeof(buf));
483 if (nread == -1)
484 errExit("read");
485
486 printf("Read %zd bytes\n", nread);
487
488 exit(EXIT_SUCCESS);
489 }
490
492 open(2), libblkid(3), blkid(8), findfs(8), mount(8)
493
494 The libblkid and libmount documentation in the latest util-linux re‐
495 lease at ⟨https://www.kernel.org/pub/linux/utils/util-linux/⟩
496
498 This page is part of release 5.10 of the Linux man-pages project. A
499 description of the project, information about reporting bugs, and the
500 latest version of this page, can be found at
501 https://www.kernel.org/doc/man-pages/.
502
503
504
505Linux 2020-11-01 OPEN_BY_HANDLE_AT(2)