Путеводитель по Руководству Linux

  User  |  Syst  |  Libr  |  Device  |  Files  |  Other  |  Admin  |  Head  |



   open_by_handle_at    ( 2 )

получить дескриптор для имени пути и открыть файл через дескриптор (obtain handle for a pathname and open file via a handle)

  Name  |  Synopsis  |  Description  |  Return value  |  Error  |  Versions  |  Conforming to  |  Note  |    Examples    |  See also  |

Примеры (Examples)

The two programs below demonstrate the use of name_to_handle_at()
       and open_by_handle_at().  The first program
       (t_name_to_handle_at.c) uses name_to_handle_at() to obtain the
       file handle and mount ID for the file specified in its command-
       line argument; the handle and mount ID are written to standard
       output.

The second program (t_open_by_handle_at.c) reads a mount ID and file handle from standard input. The program then employs open_by_handle_at() to open the file using that handle. If an optional command-line argument is supplied, then the mount_fd argument for open_by_handle_at() is obtained by opening the directory named in that argument. Otherwise, mount_fd is obtained by scanning /proc/self/mountinfo to find a record whose mount ID matches the mount ID read from standard input, and the mount directory specified in that record is opened. (These programs do not deal with the fact that mount IDs are not persistent.)

The following shell session demonstrates the use of these two programs:

$ echo 'Can you please think about it?' > cecilia.txt $ ./t_name_to_handle_at cecilia.txt > fh $ ./t_open_by_handle_at < fh open_by_handle_at: Operation not permitted $ sudo ./t_open_by_handle_at < fh # Need CAP_SYS_ADMIN Read 31 bytes $ rm cecilia.txt

Now we delete and (quickly) re-create the file so that it has the same content and (by chance) the same inode. Nevertheless, open_by_handle_at() recognizes that the original file referred to by the file handle no longer exists.

$ stat --printf="%i\n" cecilia.txt # Display inode number 4072121 $ rm cecilia.txt $ echo 'Can you please think about it?' > cecilia.txt $ stat --printf="%i\n" cecilia.txt # Check inode number 4072121 $ sudo ./t_open_by_handle_at < fh open_by_handle_at: Stale NFS file handle

Program source: t_name_to_handle_at.c

#define _GNU_SOURCE #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h>

#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0)

int main(int argc, char *argv[]) { struct file_handle *fhp; int mount_id, fhsize, flags, dirfd; char *pathname;

if (argc != 2) { fprintf(stderr, "Usage: %s pathname\n", argv[0]); exit(EXIT_FAILURE); }

pathname = argv[1];

/* Allocate file_handle structure. */

fhsize = sizeof(*fhp); fhp = malloc(fhsize); if (fhp == NULL) errExit("malloc");

/* Make an initial call to name_to_handle_at() to discover the size required for file handle. */

dirfd = AT_FDCWD; /* For name_to_handle_at() calls */ flags = 0; /* For name_to_handle_at() calls */ fhp->handle_bytes = 0; if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) != -1 || errno != EOVERFLOW) { fprintf(stderr, "Unexpected result from name_to_handle_at()\n"); exit(EXIT_FAILURE); }

/* Reallocate file_handle structure with correct size. */

fhsize = sizeof(*fhp) + fhp->handle_bytes; fhp = realloc(fhp, fhsize); /* Copies fhp->handle_bytes */ if (fhp == NULL) errExit("realloc");

/* Get file handle from pathname supplied on command line. */

if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == -1) errExit("name_to_handle_at");

/* Write mount ID, file handle size, and file handle to stdout, for later reuse by t_open_by_handle_at.c. */

printf("%d\n", mount_id); printf("%u %d ", fhp->handle_bytes, fhp->handle_type); for (int j = 0; j < fhp->handle_bytes; j++) printf(" %02x", fhp->f_handle[j]); printf("\n");

exit(EXIT_SUCCESS); }

Program source: t_open_by_handle_at.c

#define _GNU_SOURCE #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h>

#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0)

/* Scan /proc/self/mountinfo to find the line whose mount ID matches 'mount_id'. (An easier way to do this is to install and use the 'libmount' library provided by the 'util-linux' project.) Open the corresponding mount path and return the resulting file descriptor. */

static int open_mount_path_by_id(int mount_id) { char *linep; size_t lsize; char mount_path[PATH_MAX]; int mi_mount_id, found; ssize_t nread; FILE *fp;

fp = fopen("/proc/self/mountinfo", "r"); if (fp == NULL) errExit("fopen");

found = 0; linep = NULL; while (!found) { nread = getline(&linep, &lsize, fp); if (nread == -1) break;

nread = sscanf(linep, "%d %*d %*s %*s %s", &mi_mount_id, mount_path); if (nread != 2) { fprintf(stderr, "Bad sscanf()\n"); exit(EXIT_FAILURE); }

if (mi_mount_id == mount_id) found = 1; } free(linep);

fclose(fp);

if (!found) { fprintf(stderr, "Could not find mount point\n"); exit(EXIT_FAILURE); }

return open(mount_path, O_RDONLY); }

int main(int argc, char *argv[]) { struct file_handle *fhp; int mount_id, fd, mount_fd, handle_bytes; ssize_t nread; char buf[1000]; #define LINE_SIZE 100 char line1[LINE_SIZE], line2[LINE_SIZE]; char *nextp;

if ((argc > 1 && strcmp(argv[1], "--help") == 0) || argc > 2) { fprintf(stderr, "Usage: %s [mount-path]\n", argv[0]); exit(EXIT_FAILURE); }

/* Standard input contains mount ID and file handle information:

Line 1: <mount_id> Line 2: <handle_bytes> <handle_type> <bytes of handle in hex> */

if ((fgets(line1, sizeof(line1), stdin) == NULL) || (fgets(line2, sizeof(line2), stdin) == NULL)) { fprintf(stderr, "Missing mount_id / file handle\n"); exit(EXIT_FAILURE); }

mount_id = atoi(line1);

handle_bytes = strtoul(line2, &nextp, 0);

/* Given handle_bytes, we can now allocate file_handle structure. */

fhp = malloc(sizeof(*fhp) + handle_bytes); if (fhp == NULL) errExit("malloc");

fhp->handle_bytes = handle_bytes;

fhp->handle_type = strtoul(nextp, &nextp, 0);

for (int j = 0; j < fhp->handle_bytes; j++) fhp->f_handle[j] = strtoul(nextp, &nextp, 16);

/* Obtain file descriptor for mount point, either by opening the pathname specified on the command line, or by scanning /proc/self/mounts to find a mount that matches the 'mount_id' that we received from stdin. */

if (argc > 1) mount_fd = open(argv[1], O_RDONLY); else mount_fd = open_mount_path_by_id(mount_id);

if (mount_fd == -1) errExit("opening mount fd");

/* Open file using handle and mount point. */

fd = open_by_handle_at(mount_fd, fhp, O_RDONLY); if (fd == -1) errExit("open_by_handle_at");

/* Try reading a few bytes from the file. */

nread = read(fd, buf, sizeof(buf)); if (nread == -1) errExit("read");

printf("Read %zd bytes\n", nread);

exit(EXIT_SUCCESS); }