1
2
3
4
5
6
7
8
9
10
11#include "libbb.h"
12
13
14#include <linux/version.h>
15#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
16#include <linux/loop.h>
17typedef struct loop_info64 bb_loop_info;
18#define BB_LOOP_SET_STATUS LOOP_SET_STATUS64
19#define BB_LOOP_GET_STATUS LOOP_GET_STATUS64
20
21
22#else
23
24#include <linux/posix_types.h>
25#define LO_NAME_SIZE 64
26#define LO_KEY_SIZE 32
27#define LOOP_SET_FD 0x4C00
28#define LOOP_CLR_FD 0x4C01
29#define BB_LOOP_SET_STATUS 0x4C02
30#define BB_LOOP_GET_STATUS 0x4C03
31typedef struct {
32 int lo_number;
33 __kernel_dev_t lo_device;
34 unsigned long lo_inode;
35 __kernel_dev_t lo_rdevice;
36 int lo_offset;
37 int lo_encrypt_type;
38 int lo_encrypt_key_size;
39 int lo_flags;
40 char lo_file_name[LO_NAME_SIZE];
41 unsigned char lo_encrypt_key[LO_KEY_SIZE];
42 unsigned long lo_init[2];
43 char reserved[4];
44} bb_loop_info;
45#endif
46
47char* FAST_FUNC query_loop(const char *device)
48{
49 int fd;
50 bb_loop_info loopinfo;
51 char *dev = 0;
52
53 fd = open(device, O_RDONLY);
54 if (fd < 0) return 0;
55 if (!ioctl(fd, BB_LOOP_GET_STATUS, &loopinfo))
56 dev = xasprintf("%ld %s", (long) loopinfo.lo_offset,
57 (char *)loopinfo.lo_file_name);
58 close(fd);
59
60 return dev;
61}
62
63
64int FAST_FUNC del_loop(const char *device)
65{
66 int fd, rc;
67
68 fd = open(device, O_RDONLY);
69 if (fd < 0) return 1;
70 rc = ioctl(fd, LOOP_CLR_FD, 0);
71 close(fd);
72
73 return rc;
74}
75
76
77
78
79
80
81
82int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset)
83{
84 char dev[LOOP_NAMESIZE];
85 char *try;
86 bb_loop_info loopinfo;
87 struct stat statbuf;
88 int i, dfd, ffd, mode, rc = -1;
89
90
91 mode = O_RDWR;
92 ffd = open(file, mode);
93 if (ffd < 0) {
94 mode = O_RDONLY;
95 ffd = open(file, mode);
96 if (ffd < 0)
97 return -errno;
98 }
99
100
101 try = *device ? : dev;
102 for (i = 0; rc; i++) {
103 sprintf(dev, LOOP_FORMAT, i);
104
105
106 if (stat(try, &statbuf) || !S_ISBLK(statbuf.st_mode)) {
107 rc = -ENOENT;
108 break;
109 }
110
111 dfd = open(try, mode);
112 if (dfd < 0 && errno == EROFS) {
113 mode = O_RDONLY;
114 dfd = open(try, mode);
115 }
116 if (dfd < 0)
117 goto try_again;
118
119 rc = ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo);
120
121
122 if (rc && errno == ENXIO) {
123 memset(&loopinfo, 0, sizeof(loopinfo));
124 safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
125 loopinfo.lo_offset = offset;
126
127 if (!ioctl(dfd, LOOP_SET_FD, ffd)) {
128 if (!ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo))
129 rc = 0;
130 else
131 ioctl(dfd, LOOP_CLR_FD, 0);
132 }
133
134
135
136
137
138
139 } else if (strcmp(file, (char *)loopinfo.lo_file_name) != 0
140 || offset != loopinfo.lo_offset) {
141 rc = -1;
142 }
143 close(dfd);
144 try_again:
145 if (*device) break;
146 }
147 close(ffd);
148 if (!rc) {
149 if (!*device)
150 *device = xstrdup(dev);
151 return (mode == O_RDONLY);
152 }
153 return rc;
154}
155