1*508ec739SDaniel Rosenberg // SPDX-License-Identifier: GPL-2.0-or-later
2*508ec739SDaniel Rosenberg /*
3*508ec739SDaniel Rosenberg * Copyright (C) 2021 LG Electronics.
4*508ec739SDaniel Rosenberg *
5*508ec739SDaniel Rosenberg * Author(s): Hyunchul Lee <[email protected]>
6*508ec739SDaniel Rosenberg */
7*508ec739SDaniel Rosenberg #include <stdlib.h>
8*508ec739SDaniel Rosenberg #include <stdio.h>
9*508ec739SDaniel Rosenberg #include <errno.h>
10*508ec739SDaniel Rosenberg #include <fcntl.h>
11*508ec739SDaniel Rosenberg #include <string.h>
12*508ec739SDaniel Rosenberg #include <time.h>
13*508ec739SDaniel Rosenberg
14*508ec739SDaniel Rosenberg #include "exfat_ondisk.h"
15*508ec739SDaniel Rosenberg #include "libexfat.h"
16*508ec739SDaniel Rosenberg #include "exfat_fs.h"
17*508ec739SDaniel Rosenberg #include "exfat_dir.h"
18*508ec739SDaniel Rosenberg
19*508ec739SDaniel Rosenberg static struct path_resolve_ctx path_resolve_ctx;
20*508ec739SDaniel Rosenberg
21*508ec739SDaniel Rosenberg #define fsck_err(parent, inode, fmt, ...) \
22*508ec739SDaniel Rosenberg ({ \
23*508ec739SDaniel Rosenberg exfat_resolve_path_parent(&path_resolve_ctx, \
24*508ec739SDaniel Rosenberg parent, inode); \
25*508ec739SDaniel Rosenberg exfat_err("ERROR: %s: " fmt, \
26*508ec739SDaniel Rosenberg path_resolve_ctx.local_path, \
27*508ec739SDaniel Rosenberg ##__VA_ARGS__); \
28*508ec739SDaniel Rosenberg })
29*508ec739SDaniel Rosenberg
write_block(struct exfat_de_iter * iter,unsigned int block)30*508ec739SDaniel Rosenberg static ssize_t write_block(struct exfat_de_iter *iter, unsigned int block)
31*508ec739SDaniel Rosenberg {
32*508ec739SDaniel Rosenberg off_t device_offset;
33*508ec739SDaniel Rosenberg struct exfat *exfat = iter->exfat;
34*508ec739SDaniel Rosenberg struct buffer_desc *desc;
35*508ec739SDaniel Rosenberg unsigned int i;
36*508ec739SDaniel Rosenberg
37*508ec739SDaniel Rosenberg desc = &iter->buffer_desc[block & 0x01];
38*508ec739SDaniel Rosenberg
39*508ec739SDaniel Rosenberg for (i = 0; i < iter->read_size / iter->write_size; i++) {
40*508ec739SDaniel Rosenberg if (desc->dirty[i]) {
41*508ec739SDaniel Rosenberg device_offset = exfat_c2o(exfat, desc->p_clus) +
42*508ec739SDaniel Rosenberg desc->offset;
43*508ec739SDaniel Rosenberg if (exfat_write(exfat->blk_dev->dev_fd,
44*508ec739SDaniel Rosenberg desc->buffer + i * iter->write_size,
45*508ec739SDaniel Rosenberg iter->write_size,
46*508ec739SDaniel Rosenberg device_offset + i * iter->write_size)
47*508ec739SDaniel Rosenberg != (ssize_t)iter->write_size)
48*508ec739SDaniel Rosenberg return -EIO;
49*508ec739SDaniel Rosenberg desc->dirty[i] = 0;
50*508ec739SDaniel Rosenberg }
51*508ec739SDaniel Rosenberg }
52*508ec739SDaniel Rosenberg return 0;
53*508ec739SDaniel Rosenberg }
54*508ec739SDaniel Rosenberg
read_ahead_first_blocks(struct exfat_de_iter * iter)55*508ec739SDaniel Rosenberg static int read_ahead_first_blocks(struct exfat_de_iter *iter)
56*508ec739SDaniel Rosenberg {
57*508ec739SDaniel Rosenberg #ifdef POSIX_FADV_WILLNEED
58*508ec739SDaniel Rosenberg struct exfat *exfat = iter->exfat;
59*508ec739SDaniel Rosenberg clus_t clus_count;
60*508ec739SDaniel Rosenberg unsigned int size;
61*508ec739SDaniel Rosenberg
62*508ec739SDaniel Rosenberg clus_count = iter->parent->size / exfat->clus_size;
63*508ec739SDaniel Rosenberg
64*508ec739SDaniel Rosenberg if (clus_count > 1) {
65*508ec739SDaniel Rosenberg iter->ra_begin_offset = 0;
66*508ec739SDaniel Rosenberg iter->ra_next_clus = 1;
67*508ec739SDaniel Rosenberg size = exfat->clus_size;
68*508ec739SDaniel Rosenberg } else {
69*508ec739SDaniel Rosenberg iter->ra_begin_offset = 0;
70*508ec739SDaniel Rosenberg iter->ra_next_clus = 0;
71*508ec739SDaniel Rosenberg size = iter->ra_partial_size;
72*508ec739SDaniel Rosenberg }
73*508ec739SDaniel Rosenberg return posix_fadvise(exfat->blk_dev->dev_fd,
74*508ec739SDaniel Rosenberg exfat_c2o(exfat, iter->parent->first_clus), size,
75*508ec739SDaniel Rosenberg POSIX_FADV_WILLNEED);
76*508ec739SDaniel Rosenberg #else
77*508ec739SDaniel Rosenberg return -ENOTSUP;
78*508ec739SDaniel Rosenberg #endif
79*508ec739SDaniel Rosenberg }
80*508ec739SDaniel Rosenberg
81*508ec739SDaniel Rosenberg /**
82*508ec739SDaniel Rosenberg * read the next fragment in advance, and assume the fragment
83*508ec739SDaniel Rosenberg * which covers @clus is already read.
84*508ec739SDaniel Rosenberg */
read_ahead_next_blocks(struct exfat_de_iter * iter,clus_t clus,unsigned int offset,clus_t p_clus)85*508ec739SDaniel Rosenberg static int read_ahead_next_blocks(struct exfat_de_iter *iter,
86*508ec739SDaniel Rosenberg clus_t clus, unsigned int offset, clus_t p_clus)
87*508ec739SDaniel Rosenberg {
88*508ec739SDaniel Rosenberg #ifdef POSIX_FADV_WILLNEED
89*508ec739SDaniel Rosenberg struct exfat *exfat = iter->exfat;
90*508ec739SDaniel Rosenberg off_t device_offset;
91*508ec739SDaniel Rosenberg clus_t clus_count, ra_clus, ra_p_clus;
92*508ec739SDaniel Rosenberg unsigned int size;
93*508ec739SDaniel Rosenberg int ret = 0;
94*508ec739SDaniel Rosenberg
95*508ec739SDaniel Rosenberg clus_count = iter->parent->size / exfat->clus_size;
96*508ec739SDaniel Rosenberg if (clus + 1 < clus_count) {
97*508ec739SDaniel Rosenberg ra_clus = clus + 1;
98*508ec739SDaniel Rosenberg if (ra_clus == iter->ra_next_clus &&
99*508ec739SDaniel Rosenberg offset >= iter->ra_begin_offset) {
100*508ec739SDaniel Rosenberg ret = exfat_get_inode_next_clus(exfat, iter->parent,
101*508ec739SDaniel Rosenberg p_clus, &ra_p_clus);
102*508ec739SDaniel Rosenberg if (ret)
103*508ec739SDaniel Rosenberg return ret;
104*508ec739SDaniel Rosenberg
105*508ec739SDaniel Rosenberg if (ra_p_clus == EXFAT_EOF_CLUSTER)
106*508ec739SDaniel Rosenberg return -EIO;
107*508ec739SDaniel Rosenberg
108*508ec739SDaniel Rosenberg device_offset = exfat_c2o(exfat, ra_p_clus);
109*508ec739SDaniel Rosenberg size = ra_clus + 1 < clus_count ?
110*508ec739SDaniel Rosenberg exfat->clus_size : iter->ra_partial_size;
111*508ec739SDaniel Rosenberg ret = posix_fadvise(exfat->blk_dev->dev_fd,
112*508ec739SDaniel Rosenberg device_offset, size,
113*508ec739SDaniel Rosenberg POSIX_FADV_WILLNEED);
114*508ec739SDaniel Rosenberg iter->ra_next_clus = ra_clus + 1;
115*508ec739SDaniel Rosenberg iter->ra_begin_offset = 0;
116*508ec739SDaniel Rosenberg }
117*508ec739SDaniel Rosenberg } else {
118*508ec739SDaniel Rosenberg if (offset >= iter->ra_begin_offset &&
119*508ec739SDaniel Rosenberg offset + iter->ra_partial_size <=
120*508ec739SDaniel Rosenberg exfat->clus_size) {
121*508ec739SDaniel Rosenberg device_offset = exfat_c2o(exfat, p_clus) +
122*508ec739SDaniel Rosenberg offset + iter->ra_partial_size;
123*508ec739SDaniel Rosenberg ret = posix_fadvise(exfat->blk_dev->dev_fd,
124*508ec739SDaniel Rosenberg device_offset, iter->ra_partial_size,
125*508ec739SDaniel Rosenberg POSIX_FADV_WILLNEED);
126*508ec739SDaniel Rosenberg iter->ra_begin_offset =
127*508ec739SDaniel Rosenberg offset + iter->ra_partial_size;
128*508ec739SDaniel Rosenberg }
129*508ec739SDaniel Rosenberg }
130*508ec739SDaniel Rosenberg
131*508ec739SDaniel Rosenberg return ret;
132*508ec739SDaniel Rosenberg #else
133*508ec739SDaniel Rosenberg return -ENOTSUP;
134*508ec739SDaniel Rosenberg #endif
135*508ec739SDaniel Rosenberg }
136*508ec739SDaniel Rosenberg
read_ahead_next_dir_blocks(struct exfat_de_iter * iter)137*508ec739SDaniel Rosenberg static int read_ahead_next_dir_blocks(struct exfat_de_iter *iter)
138*508ec739SDaniel Rosenberg {
139*508ec739SDaniel Rosenberg #ifdef POSIX_FADV_WILLNEED
140*508ec739SDaniel Rosenberg struct exfat *exfat = iter->exfat;
141*508ec739SDaniel Rosenberg struct list_head *current;
142*508ec739SDaniel Rosenberg struct exfat_inode *next_inode;
143*508ec739SDaniel Rosenberg off_t offset;
144*508ec739SDaniel Rosenberg
145*508ec739SDaniel Rosenberg if (list_empty(&exfat->dir_list))
146*508ec739SDaniel Rosenberg return -EINVAL;
147*508ec739SDaniel Rosenberg
148*508ec739SDaniel Rosenberg current = exfat->dir_list.next;
149*508ec739SDaniel Rosenberg if (iter->parent == list_entry(current, struct exfat_inode, list) &&
150*508ec739SDaniel Rosenberg current->next != &exfat->dir_list) {
151*508ec739SDaniel Rosenberg next_inode = list_entry(current->next, struct exfat_inode,
152*508ec739SDaniel Rosenberg list);
153*508ec739SDaniel Rosenberg offset = exfat_c2o(exfat, next_inode->first_clus);
154*508ec739SDaniel Rosenberg return posix_fadvise(exfat->blk_dev->dev_fd, offset,
155*508ec739SDaniel Rosenberg iter->ra_partial_size,
156*508ec739SDaniel Rosenberg POSIX_FADV_WILLNEED);
157*508ec739SDaniel Rosenberg }
158*508ec739SDaniel Rosenberg
159*508ec739SDaniel Rosenberg return 0;
160*508ec739SDaniel Rosenberg #else
161*508ec739SDaniel Rosenberg return -ENOTSUP;
162*508ec739SDaniel Rosenberg #endif
163*508ec739SDaniel Rosenberg }
164*508ec739SDaniel Rosenberg
read_block(struct exfat_de_iter * iter,unsigned int block)165*508ec739SDaniel Rosenberg static ssize_t read_block(struct exfat_de_iter *iter, unsigned int block)
166*508ec739SDaniel Rosenberg {
167*508ec739SDaniel Rosenberg struct exfat *exfat = iter->exfat;
168*508ec739SDaniel Rosenberg struct buffer_desc *desc, *prev_desc;
169*508ec739SDaniel Rosenberg off_t device_offset;
170*508ec739SDaniel Rosenberg ssize_t ret;
171*508ec739SDaniel Rosenberg
172*508ec739SDaniel Rosenberg desc = &iter->buffer_desc[block & 0x01];
173*508ec739SDaniel Rosenberg if (block == 0) {
174*508ec739SDaniel Rosenberg desc->p_clus = iter->parent->first_clus;
175*508ec739SDaniel Rosenberg desc->offset = 0;
176*508ec739SDaniel Rosenberg }
177*508ec739SDaniel Rosenberg
178*508ec739SDaniel Rosenberg /* if the buffer already contains dirty dentries, write it */
179*508ec739SDaniel Rosenberg if (write_block(iter, block))
180*508ec739SDaniel Rosenberg return -EIO;
181*508ec739SDaniel Rosenberg
182*508ec739SDaniel Rosenberg if (block > 0) {
183*508ec739SDaniel Rosenberg if (block > iter->parent->size / iter->read_size)
184*508ec739SDaniel Rosenberg return EOF;
185*508ec739SDaniel Rosenberg
186*508ec739SDaniel Rosenberg prev_desc = &iter->buffer_desc[(block-1) & 0x01];
187*508ec739SDaniel Rosenberg if (prev_desc->offset + 2 * iter->read_size <=
188*508ec739SDaniel Rosenberg exfat->clus_size) {
189*508ec739SDaniel Rosenberg desc->p_clus = prev_desc->p_clus;
190*508ec739SDaniel Rosenberg desc->offset = prev_desc->offset + iter->read_size;
191*508ec739SDaniel Rosenberg } else {
192*508ec739SDaniel Rosenberg ret = exfat_get_inode_next_clus(exfat, iter->parent,
193*508ec739SDaniel Rosenberg prev_desc->p_clus, &desc->p_clus);
194*508ec739SDaniel Rosenberg desc->offset = 0;
195*508ec739SDaniel Rosenberg if (ret)
196*508ec739SDaniel Rosenberg return ret;
197*508ec739SDaniel Rosenberg else if (desc->p_clus == EXFAT_EOF_CLUSTER)
198*508ec739SDaniel Rosenberg return EOF;
199*508ec739SDaniel Rosenberg }
200*508ec739SDaniel Rosenberg }
201*508ec739SDaniel Rosenberg
202*508ec739SDaniel Rosenberg device_offset = exfat_c2o(exfat, desc->p_clus) + desc->offset;
203*508ec739SDaniel Rosenberg ret = exfat_read(exfat->blk_dev->dev_fd, desc->buffer,
204*508ec739SDaniel Rosenberg iter->read_size, device_offset);
205*508ec739SDaniel Rosenberg if (ret <= 0)
206*508ec739SDaniel Rosenberg return ret;
207*508ec739SDaniel Rosenberg
208*508ec739SDaniel Rosenberg /*
209*508ec739SDaniel Rosenberg * if a buffer is filled with dentries, read blocks ahead of time,
210*508ec739SDaniel Rosenberg * otherwise read blocks of the next directory in advance.
211*508ec739SDaniel Rosenberg */
212*508ec739SDaniel Rosenberg if (desc->buffer[iter->read_size - 32] != EXFAT_LAST)
213*508ec739SDaniel Rosenberg read_ahead_next_blocks(iter,
214*508ec739SDaniel Rosenberg (block * iter->read_size) / exfat->clus_size,
215*508ec739SDaniel Rosenberg (block * iter->read_size) % exfat->clus_size,
216*508ec739SDaniel Rosenberg desc->p_clus);
217*508ec739SDaniel Rosenberg else
218*508ec739SDaniel Rosenberg read_ahead_next_dir_blocks(iter);
219*508ec739SDaniel Rosenberg return ret;
220*508ec739SDaniel Rosenberg }
221*508ec739SDaniel Rosenberg
exfat_de_iter_init(struct exfat_de_iter * iter,struct exfat * exfat,struct exfat_inode * dir,struct buffer_desc * bd)222*508ec739SDaniel Rosenberg int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat,
223*508ec739SDaniel Rosenberg struct exfat_inode *dir, struct buffer_desc *bd)
224*508ec739SDaniel Rosenberg {
225*508ec739SDaniel Rosenberg iter->exfat = exfat;
226*508ec739SDaniel Rosenberg iter->parent = dir;
227*508ec739SDaniel Rosenberg iter->write_size = exfat->sect_size;
228*508ec739SDaniel Rosenberg iter->read_size = exfat->clus_size <= 4*KB ? exfat->clus_size : 4*KB;
229*508ec739SDaniel Rosenberg if (exfat->clus_size <= 32 * KB)
230*508ec739SDaniel Rosenberg iter->ra_partial_size = MAX(4 * KB, exfat->clus_size / 2);
231*508ec739SDaniel Rosenberg else
232*508ec739SDaniel Rosenberg iter->ra_partial_size = exfat->clus_size / 4;
233*508ec739SDaniel Rosenberg iter->ra_partial_size = MIN(iter->ra_partial_size, 8 * KB);
234*508ec739SDaniel Rosenberg
235*508ec739SDaniel Rosenberg iter->buffer_desc = bd;
236*508ec739SDaniel Rosenberg
237*508ec739SDaniel Rosenberg iter->de_file_offset = 0;
238*508ec739SDaniel Rosenberg iter->next_read_offset = iter->read_size;
239*508ec739SDaniel Rosenberg iter->max_skip_dentries = 0;
240*508ec739SDaniel Rosenberg iter->dot_name_num = 0;
241*508ec739SDaniel Rosenberg
242*508ec739SDaniel Rosenberg if (iter->parent->size == 0)
243*508ec739SDaniel Rosenberg return EOF;
244*508ec739SDaniel Rosenberg
245*508ec739SDaniel Rosenberg read_ahead_first_blocks(iter);
246*508ec739SDaniel Rosenberg if (read_block(iter, 0) != (ssize_t)iter->read_size) {
247*508ec739SDaniel Rosenberg exfat_err("failed to read directory entries.\n");
248*508ec739SDaniel Rosenberg return -EIO;
249*508ec739SDaniel Rosenberg }
250*508ec739SDaniel Rosenberg
251*508ec739SDaniel Rosenberg return 0;
252*508ec739SDaniel Rosenberg }
253*508ec739SDaniel Rosenberg
exfat_de_iter_get(struct exfat_de_iter * iter,int ith,struct exfat_dentry ** dentry)254*508ec739SDaniel Rosenberg int exfat_de_iter_get(struct exfat_de_iter *iter,
255*508ec739SDaniel Rosenberg int ith, struct exfat_dentry **dentry)
256*508ec739SDaniel Rosenberg {
257*508ec739SDaniel Rosenberg off_t next_de_file_offset;
258*508ec739SDaniel Rosenberg ssize_t ret;
259*508ec739SDaniel Rosenberg unsigned int block;
260*508ec739SDaniel Rosenberg
261*508ec739SDaniel Rosenberg next_de_file_offset = iter->de_file_offset +
262*508ec739SDaniel Rosenberg ith * sizeof(struct exfat_dentry);
263*508ec739SDaniel Rosenberg block = (unsigned int)(next_de_file_offset / iter->read_size);
264*508ec739SDaniel Rosenberg
265*508ec739SDaniel Rosenberg if (next_de_file_offset + sizeof(struct exfat_dentry) >
266*508ec739SDaniel Rosenberg iter->parent->size)
267*508ec739SDaniel Rosenberg return EOF;
268*508ec739SDaniel Rosenberg /* the dentry must be in current, or next block which will be read */
269*508ec739SDaniel Rosenberg if (block > iter->de_file_offset / iter->read_size + 1)
270*508ec739SDaniel Rosenberg return -ERANGE;
271*508ec739SDaniel Rosenberg
272*508ec739SDaniel Rosenberg /* read next cluster if needed */
273*508ec739SDaniel Rosenberg if (next_de_file_offset >= iter->next_read_offset) {
274*508ec739SDaniel Rosenberg ret = read_block(iter, block);
275*508ec739SDaniel Rosenberg if (ret != (ssize_t)iter->read_size)
276*508ec739SDaniel Rosenberg return ret;
277*508ec739SDaniel Rosenberg iter->next_read_offset += iter->read_size;
278*508ec739SDaniel Rosenberg }
279*508ec739SDaniel Rosenberg
280*508ec739SDaniel Rosenberg if (ith + 1 > iter->max_skip_dentries)
281*508ec739SDaniel Rosenberg iter->max_skip_dentries = ith + 1;
282*508ec739SDaniel Rosenberg
283*508ec739SDaniel Rosenberg *dentry = (struct exfat_dentry *)
284*508ec739SDaniel Rosenberg (iter->buffer_desc[block & 0x01].buffer +
285*508ec739SDaniel Rosenberg next_de_file_offset % iter->read_size);
286*508ec739SDaniel Rosenberg return 0;
287*508ec739SDaniel Rosenberg }
288*508ec739SDaniel Rosenberg
exfat_de_iter_get_dirty(struct exfat_de_iter * iter,int ith,struct exfat_dentry ** dentry)289*508ec739SDaniel Rosenberg int exfat_de_iter_get_dirty(struct exfat_de_iter *iter,
290*508ec739SDaniel Rosenberg int ith, struct exfat_dentry **dentry)
291*508ec739SDaniel Rosenberg {
292*508ec739SDaniel Rosenberg off_t next_file_offset;
293*508ec739SDaniel Rosenberg unsigned int block;
294*508ec739SDaniel Rosenberg int ret, sect_idx;
295*508ec739SDaniel Rosenberg
296*508ec739SDaniel Rosenberg ret = exfat_de_iter_get(iter, ith, dentry);
297*508ec739SDaniel Rosenberg if (!ret) {
298*508ec739SDaniel Rosenberg next_file_offset = iter->de_file_offset +
299*508ec739SDaniel Rosenberg ith * sizeof(struct exfat_dentry);
300*508ec739SDaniel Rosenberg block = (unsigned int)(next_file_offset / iter->read_size);
301*508ec739SDaniel Rosenberg sect_idx = (int)((next_file_offset % iter->read_size) /
302*508ec739SDaniel Rosenberg iter->write_size);
303*508ec739SDaniel Rosenberg iter->buffer_desc[block & 0x01].dirty[sect_idx] = 1;
304*508ec739SDaniel Rosenberg }
305*508ec739SDaniel Rosenberg
306*508ec739SDaniel Rosenberg return ret;
307*508ec739SDaniel Rosenberg }
308*508ec739SDaniel Rosenberg
exfat_de_iter_flush(struct exfat_de_iter * iter)309*508ec739SDaniel Rosenberg int exfat_de_iter_flush(struct exfat_de_iter *iter)
310*508ec739SDaniel Rosenberg {
311*508ec739SDaniel Rosenberg if (write_block(iter, 0) || write_block(iter, 1))
312*508ec739SDaniel Rosenberg return -EIO;
313*508ec739SDaniel Rosenberg return 0;
314*508ec739SDaniel Rosenberg }
315*508ec739SDaniel Rosenberg
exfat_de_iter_advance(struct exfat_de_iter * iter,int skip_dentries)316*508ec739SDaniel Rosenberg int exfat_de_iter_advance(struct exfat_de_iter *iter, int skip_dentries)
317*508ec739SDaniel Rosenberg {
318*508ec739SDaniel Rosenberg if (skip_dentries > iter->max_skip_dentries)
319*508ec739SDaniel Rosenberg return -EINVAL;
320*508ec739SDaniel Rosenberg
321*508ec739SDaniel Rosenberg iter->max_skip_dentries = 0;
322*508ec739SDaniel Rosenberg iter->de_file_offset = iter->de_file_offset +
323*508ec739SDaniel Rosenberg skip_dentries * sizeof(struct exfat_dentry);
324*508ec739SDaniel Rosenberg return 0;
325*508ec739SDaniel Rosenberg }
326*508ec739SDaniel Rosenberg
exfat_de_iter_device_offset(struct exfat_de_iter * iter)327*508ec739SDaniel Rosenberg off_t exfat_de_iter_device_offset(struct exfat_de_iter *iter)
328*508ec739SDaniel Rosenberg {
329*508ec739SDaniel Rosenberg struct buffer_desc *bd;
330*508ec739SDaniel Rosenberg unsigned int block;
331*508ec739SDaniel Rosenberg
332*508ec739SDaniel Rosenberg if ((uint64_t)iter->de_file_offset >= iter->parent->size)
333*508ec739SDaniel Rosenberg return EOF;
334*508ec739SDaniel Rosenberg
335*508ec739SDaniel Rosenberg block = iter->de_file_offset / iter->read_size;
336*508ec739SDaniel Rosenberg bd = &iter->buffer_desc[block & 0x01];
337*508ec739SDaniel Rosenberg return exfat_c2o(iter->exfat, bd->p_clus) + bd->offset +
338*508ec739SDaniel Rosenberg iter->de_file_offset % iter->read_size;
339*508ec739SDaniel Rosenberg }
340*508ec739SDaniel Rosenberg
exfat_de_iter_file_offset(struct exfat_de_iter * iter)341*508ec739SDaniel Rosenberg off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter)
342*508ec739SDaniel Rosenberg {
343*508ec739SDaniel Rosenberg return iter->de_file_offset;
344*508ec739SDaniel Rosenberg }
345*508ec739SDaniel Rosenberg
346*508ec739SDaniel Rosenberg /*
347*508ec739SDaniel Rosenberg * try to find the dentry set matched with @filter. this function
348*508ec739SDaniel Rosenberg * doesn't verify the dentry set.
349*508ec739SDaniel Rosenberg *
350*508ec739SDaniel Rosenberg * if found, return 0. if not found, return EOF. otherwise return errno.
351*508ec739SDaniel Rosenberg */
exfat_lookup_dentry_set(struct exfat * exfat,struct exfat_inode * parent,struct exfat_lookup_filter * filter)352*508ec739SDaniel Rosenberg int exfat_lookup_dentry_set(struct exfat *exfat, struct exfat_inode *parent,
353*508ec739SDaniel Rosenberg struct exfat_lookup_filter *filter)
354*508ec739SDaniel Rosenberg {
355*508ec739SDaniel Rosenberg struct buffer_desc *bd = NULL;
356*508ec739SDaniel Rosenberg struct exfat_dentry *dentry = NULL;
357*508ec739SDaniel Rosenberg off_t free_file_offset = 0, free_dev_offset = 0;
358*508ec739SDaniel Rosenberg struct exfat_de_iter de_iter;
359*508ec739SDaniel Rosenberg int dentry_count;
360*508ec739SDaniel Rosenberg int retval;
361*508ec739SDaniel Rosenberg bool last_is_free = false;
362*508ec739SDaniel Rosenberg
363*508ec739SDaniel Rosenberg bd = exfat_alloc_buffer(2, exfat->clus_size, exfat->sect_size);
364*508ec739SDaniel Rosenberg if (!bd)
365*508ec739SDaniel Rosenberg return -ENOMEM;
366*508ec739SDaniel Rosenberg
367*508ec739SDaniel Rosenberg retval = exfat_de_iter_init(&de_iter, exfat, parent, bd);
368*508ec739SDaniel Rosenberg if (retval == EOF || retval)
369*508ec739SDaniel Rosenberg goto out;
370*508ec739SDaniel Rosenberg
371*508ec739SDaniel Rosenberg filter->out.dentry_set = NULL;
372*508ec739SDaniel Rosenberg while (1) {
373*508ec739SDaniel Rosenberg retval = exfat_de_iter_get(&de_iter, 0, &dentry);
374*508ec739SDaniel Rosenberg if (retval == EOF) {
375*508ec739SDaniel Rosenberg break;
376*508ec739SDaniel Rosenberg } else if (retval) {
377*508ec739SDaniel Rosenberg fsck_err(parent->parent, parent,
378*508ec739SDaniel Rosenberg "failed to get a dentry. %d\n", retval);
379*508ec739SDaniel Rosenberg goto out;
380*508ec739SDaniel Rosenberg }
381*508ec739SDaniel Rosenberg
382*508ec739SDaniel Rosenberg dentry_count = 1;
383*508ec739SDaniel Rosenberg if (dentry->type == filter->in.type) {
384*508ec739SDaniel Rosenberg retval = 0;
385*508ec739SDaniel Rosenberg if (filter->in.filter)
386*508ec739SDaniel Rosenberg retval = filter->in.filter(&de_iter,
387*508ec739SDaniel Rosenberg filter->in.param,
388*508ec739SDaniel Rosenberg &dentry_count);
389*508ec739SDaniel Rosenberg
390*508ec739SDaniel Rosenberg if (retval == 0) {
391*508ec739SDaniel Rosenberg struct exfat_dentry *d;
392*508ec739SDaniel Rosenberg int i;
393*508ec739SDaniel Rosenberg
394*508ec739SDaniel Rosenberg filter->out.dentry_set = calloc(dentry_count,
395*508ec739SDaniel Rosenberg sizeof(struct exfat_dentry));
396*508ec739SDaniel Rosenberg if (!filter->out.dentry_set) {
397*508ec739SDaniel Rosenberg retval = -ENOMEM;
398*508ec739SDaniel Rosenberg goto out;
399*508ec739SDaniel Rosenberg }
400*508ec739SDaniel Rosenberg for (i = 0; i < dentry_count; i++) {
401*508ec739SDaniel Rosenberg exfat_de_iter_get(&de_iter, i, &d);
402*508ec739SDaniel Rosenberg memcpy(filter->out.dentry_set + i, d,
403*508ec739SDaniel Rosenberg sizeof(struct exfat_dentry));
404*508ec739SDaniel Rosenberg }
405*508ec739SDaniel Rosenberg filter->out.dentry_count = dentry_count;
406*508ec739SDaniel Rosenberg goto out;
407*508ec739SDaniel Rosenberg } else if (retval < 0) {
408*508ec739SDaniel Rosenberg goto out;
409*508ec739SDaniel Rosenberg }
410*508ec739SDaniel Rosenberg last_is_free = false;
411*508ec739SDaniel Rosenberg } else if ((dentry->type == EXFAT_LAST ||
412*508ec739SDaniel Rosenberg IS_EXFAT_DELETED(dentry->type))) {
413*508ec739SDaniel Rosenberg if (!last_is_free) {
414*508ec739SDaniel Rosenberg free_file_offset =
415*508ec739SDaniel Rosenberg exfat_de_iter_file_offset(&de_iter);
416*508ec739SDaniel Rosenberg free_dev_offset =
417*508ec739SDaniel Rosenberg exfat_de_iter_device_offset(&de_iter);
418*508ec739SDaniel Rosenberg last_is_free = true;
419*508ec739SDaniel Rosenberg }
420*508ec739SDaniel Rosenberg } else {
421*508ec739SDaniel Rosenberg last_is_free = false;
422*508ec739SDaniel Rosenberg }
423*508ec739SDaniel Rosenberg
424*508ec739SDaniel Rosenberg exfat_de_iter_advance(&de_iter, dentry_count);
425*508ec739SDaniel Rosenberg }
426*508ec739SDaniel Rosenberg
427*508ec739SDaniel Rosenberg out:
428*508ec739SDaniel Rosenberg if (retval == 0) {
429*508ec739SDaniel Rosenberg filter->out.file_offset =
430*508ec739SDaniel Rosenberg exfat_de_iter_file_offset(&de_iter);
431*508ec739SDaniel Rosenberg filter->out.dev_offset =
432*508ec739SDaniel Rosenberg exfat_de_iter_device_offset(&de_iter);
433*508ec739SDaniel Rosenberg } else if (retval == EOF && last_is_free) {
434*508ec739SDaniel Rosenberg filter->out.file_offset = free_file_offset;
435*508ec739SDaniel Rosenberg filter->out.dev_offset = free_dev_offset;
436*508ec739SDaniel Rosenberg } else {
437*508ec739SDaniel Rosenberg filter->out.file_offset = exfat_de_iter_file_offset(&de_iter);
438*508ec739SDaniel Rosenberg filter->out.dev_offset = EOF;
439*508ec739SDaniel Rosenberg }
440*508ec739SDaniel Rosenberg if (bd)
441*508ec739SDaniel Rosenberg exfat_free_buffer(bd, 2);
442*508ec739SDaniel Rosenberg return retval;
443*508ec739SDaniel Rosenberg }
444*508ec739SDaniel Rosenberg
filter_lookup_file(struct exfat_de_iter * de_iter,void * param,int * dentry_count)445*508ec739SDaniel Rosenberg static int filter_lookup_file(struct exfat_de_iter *de_iter,
446*508ec739SDaniel Rosenberg void *param, int *dentry_count)
447*508ec739SDaniel Rosenberg {
448*508ec739SDaniel Rosenberg struct exfat_dentry *file_de, *stream_de, *name_de;
449*508ec739SDaniel Rosenberg __le16 *name;
450*508ec739SDaniel Rosenberg int retval, name_len;
451*508ec739SDaniel Rosenberg int i;
452*508ec739SDaniel Rosenberg
453*508ec739SDaniel Rosenberg retval = exfat_de_iter_get(de_iter, 0, &file_de);
454*508ec739SDaniel Rosenberg if (retval || file_de->type != EXFAT_FILE)
455*508ec739SDaniel Rosenberg return 1;
456*508ec739SDaniel Rosenberg
457*508ec739SDaniel Rosenberg retval = exfat_de_iter_get(de_iter, 1, &stream_de);
458*508ec739SDaniel Rosenberg if (retval || stream_de->type != EXFAT_STREAM)
459*508ec739SDaniel Rosenberg return 1;
460*508ec739SDaniel Rosenberg
461*508ec739SDaniel Rosenberg name = (__le16 *)param;
462*508ec739SDaniel Rosenberg name_len = (int)exfat_utf16_len(name, PATH_MAX);
463*508ec739SDaniel Rosenberg
464*508ec739SDaniel Rosenberg if (file_de->dentry.file.num_ext <
465*508ec739SDaniel Rosenberg 1 + (name_len + ENTRY_NAME_MAX - 1) / ENTRY_NAME_MAX)
466*508ec739SDaniel Rosenberg return 1;
467*508ec739SDaniel Rosenberg
468*508ec739SDaniel Rosenberg for (i = 2; i <= file_de->dentry.file.num_ext && name_len > 0; i++) {
469*508ec739SDaniel Rosenberg int len;
470*508ec739SDaniel Rosenberg
471*508ec739SDaniel Rosenberg retval = exfat_de_iter_get(de_iter, i, &name_de);
472*508ec739SDaniel Rosenberg if (retval || name_de->type != EXFAT_NAME)
473*508ec739SDaniel Rosenberg return 1;
474*508ec739SDaniel Rosenberg
475*508ec739SDaniel Rosenberg len = MIN(name_len, ENTRY_NAME_MAX);
476*508ec739SDaniel Rosenberg if (memcmp(name_de->dentry.name.unicode_0_14,
477*508ec739SDaniel Rosenberg name, len * 2) != 0)
478*508ec739SDaniel Rosenberg return 1;
479*508ec739SDaniel Rosenberg
480*508ec739SDaniel Rosenberg name += len;
481*508ec739SDaniel Rosenberg name_len -= len;
482*508ec739SDaniel Rosenberg }
483*508ec739SDaniel Rosenberg
484*508ec739SDaniel Rosenberg *dentry_count = i;
485*508ec739SDaniel Rosenberg return 0;
486*508ec739SDaniel Rosenberg }
487*508ec739SDaniel Rosenberg
exfat_lookup_file(struct exfat * exfat,struct exfat_inode * parent,const char * name,struct exfat_lookup_filter * filter_out)488*508ec739SDaniel Rosenberg int exfat_lookup_file(struct exfat *exfat, struct exfat_inode *parent,
489*508ec739SDaniel Rosenberg const char *name, struct exfat_lookup_filter *filter_out)
490*508ec739SDaniel Rosenberg {
491*508ec739SDaniel Rosenberg int retval;
492*508ec739SDaniel Rosenberg __le16 utf16_name[PATH_MAX + 2] = {0, };
493*508ec739SDaniel Rosenberg
494*508ec739SDaniel Rosenberg retval = (int)exfat_utf16_enc(name, utf16_name, sizeof(utf16_name));
495*508ec739SDaniel Rosenberg if (retval < 0)
496*508ec739SDaniel Rosenberg return retval;
497*508ec739SDaniel Rosenberg
498*508ec739SDaniel Rosenberg filter_out->in.type = EXFAT_FILE;
499*508ec739SDaniel Rosenberg filter_out->in.filter = filter_lookup_file;
500*508ec739SDaniel Rosenberg filter_out->in.param = utf16_name;
501*508ec739SDaniel Rosenberg
502*508ec739SDaniel Rosenberg retval = exfat_lookup_dentry_set(exfat, parent, filter_out);
503*508ec739SDaniel Rosenberg if (retval < 0)
504*508ec739SDaniel Rosenberg return retval;
505*508ec739SDaniel Rosenberg
506*508ec739SDaniel Rosenberg return 0;
507*508ec739SDaniel Rosenberg }
508*508ec739SDaniel Rosenberg
exfat_calc_dentry_checksum(struct exfat_dentry * dentry,uint16_t * checksum,bool primary)509*508ec739SDaniel Rosenberg void exfat_calc_dentry_checksum(struct exfat_dentry *dentry,
510*508ec739SDaniel Rosenberg uint16_t *checksum, bool primary)
511*508ec739SDaniel Rosenberg {
512*508ec739SDaniel Rosenberg unsigned int i;
513*508ec739SDaniel Rosenberg uint8_t *bytes;
514*508ec739SDaniel Rosenberg
515*508ec739SDaniel Rosenberg bytes = (uint8_t *)dentry;
516*508ec739SDaniel Rosenberg
517*508ec739SDaniel Rosenberg *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[0];
518*508ec739SDaniel Rosenberg *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[1];
519*508ec739SDaniel Rosenberg
520*508ec739SDaniel Rosenberg i = primary ? 4 : 2;
521*508ec739SDaniel Rosenberg for (; i < sizeof(*dentry); i++)
522*508ec739SDaniel Rosenberg *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[i];
523*508ec739SDaniel Rosenberg }
524*508ec739SDaniel Rosenberg
calc_dentry_set_checksum(struct exfat_dentry * dset,int dcount)525*508ec739SDaniel Rosenberg static uint16_t calc_dentry_set_checksum(struct exfat_dentry *dset, int dcount)
526*508ec739SDaniel Rosenberg {
527*508ec739SDaniel Rosenberg uint16_t checksum;
528*508ec739SDaniel Rosenberg int i;
529*508ec739SDaniel Rosenberg
530*508ec739SDaniel Rosenberg if (dcount < MIN_FILE_DENTRIES)
531*508ec739SDaniel Rosenberg return 0;
532*508ec739SDaniel Rosenberg
533*508ec739SDaniel Rosenberg checksum = 0;
534*508ec739SDaniel Rosenberg exfat_calc_dentry_checksum(&dset[0], &checksum, true);
535*508ec739SDaniel Rosenberg for (i = 1; i < dcount; i++)
536*508ec739SDaniel Rosenberg exfat_calc_dentry_checksum(&dset[i], &checksum, false);
537*508ec739SDaniel Rosenberg return checksum;
538*508ec739SDaniel Rosenberg }
539*508ec739SDaniel Rosenberg
exfat_calc_name_hash(struct exfat * exfat,__le16 * name,int len)540*508ec739SDaniel Rosenberg uint16_t exfat_calc_name_hash(struct exfat *exfat,
541*508ec739SDaniel Rosenberg __le16 *name, int len)
542*508ec739SDaniel Rosenberg {
543*508ec739SDaniel Rosenberg int i;
544*508ec739SDaniel Rosenberg __le16 ch;
545*508ec739SDaniel Rosenberg uint16_t chksum = 0;
546*508ec739SDaniel Rosenberg
547*508ec739SDaniel Rosenberg for (i = 0; i < len; i++) {
548*508ec739SDaniel Rosenberg ch = exfat->upcase_table[le16_to_cpu(name[i])];
549*508ec739SDaniel Rosenberg ch = cpu_to_le16(ch);
550*508ec739SDaniel Rosenberg
551*508ec739SDaniel Rosenberg chksum = ((chksum << 15) | (chksum >> 1)) + (ch & 0xFF);
552*508ec739SDaniel Rosenberg chksum = ((chksum << 15) | (chksum >> 1)) + (ch >> 8);
553*508ec739SDaniel Rosenberg }
554*508ec739SDaniel Rosenberg return chksum;
555*508ec739SDaniel Rosenberg }
556*508ec739SDaniel Rosenberg
unix_time_to_exfat_time(time_t unix_time,__u8 * tz,__le16 * date,__le16 * time,__u8 * time_ms)557*508ec739SDaniel Rosenberg static void unix_time_to_exfat_time(time_t unix_time, __u8 *tz, __le16 *date,
558*508ec739SDaniel Rosenberg __le16 *time, __u8 *time_ms)
559*508ec739SDaniel Rosenberg {
560*508ec739SDaniel Rosenberg struct tm tm;
561*508ec739SDaniel Rosenberg __u16 t, d;
562*508ec739SDaniel Rosenberg
563*508ec739SDaniel Rosenberg gmtime_r(&unix_time, &tm);
564*508ec739SDaniel Rosenberg d = ((tm.tm_year - 80) << 9) | ((tm.tm_mon + 1) << 5) | tm.tm_mday;
565*508ec739SDaniel Rosenberg t = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec >> 1);
566*508ec739SDaniel Rosenberg
567*508ec739SDaniel Rosenberg *tz = 0x80;
568*508ec739SDaniel Rosenberg *date = cpu_to_le16(d);
569*508ec739SDaniel Rosenberg *time = cpu_to_le16(t);
570*508ec739SDaniel Rosenberg if (time_ms)
571*508ec739SDaniel Rosenberg *time_ms = (tm.tm_sec & 1) * 100;
572*508ec739SDaniel Rosenberg }
573*508ec739SDaniel Rosenberg
exfat_build_file_dentry_set(struct exfat * exfat,const char * name,unsigned short attr,struct exfat_dentry ** dentry_set,int * dentry_count)574*508ec739SDaniel Rosenberg int exfat_build_file_dentry_set(struct exfat *exfat, const char *name,
575*508ec739SDaniel Rosenberg unsigned short attr, struct exfat_dentry **dentry_set,
576*508ec739SDaniel Rosenberg int *dentry_count)
577*508ec739SDaniel Rosenberg {
578*508ec739SDaniel Rosenberg struct exfat_dentry *dset;
579*508ec739SDaniel Rosenberg __le16 utf16_name[PATH_MAX + 2];
580*508ec739SDaniel Rosenberg int retval;
581*508ec739SDaniel Rosenberg int dcount, name_len, i;
582*508ec739SDaniel Rosenberg __le16 e_date, e_time;
583*508ec739SDaniel Rosenberg __u8 tz, e_time_ms;
584*508ec739SDaniel Rosenberg
585*508ec739SDaniel Rosenberg memset(utf16_name, 0, sizeof(utf16_name));
586*508ec739SDaniel Rosenberg retval = exfat_utf16_enc(name, utf16_name, sizeof(utf16_name));
587*508ec739SDaniel Rosenberg if (retval < 0)
588*508ec739SDaniel Rosenberg return retval;
589*508ec739SDaniel Rosenberg
590*508ec739SDaniel Rosenberg name_len = retval / 2;
591*508ec739SDaniel Rosenberg dcount = 2 + DIV_ROUND_UP(name_len, ENTRY_NAME_MAX);
592*508ec739SDaniel Rosenberg dset = calloc(1, dcount * DENTRY_SIZE);
593*508ec739SDaniel Rosenberg if (!dset)
594*508ec739SDaniel Rosenberg return -ENOMEM;
595*508ec739SDaniel Rosenberg
596*508ec739SDaniel Rosenberg dset[0].type = EXFAT_FILE;
597*508ec739SDaniel Rosenberg dset[0].dentry.file.num_ext = dcount - 1;
598*508ec739SDaniel Rosenberg dset[0].dentry.file.attr = cpu_to_le16(attr);
599*508ec739SDaniel Rosenberg
600*508ec739SDaniel Rosenberg unix_time_to_exfat_time(time(NULL), &tz,
601*508ec739SDaniel Rosenberg &e_date, &e_time, &e_time_ms);
602*508ec739SDaniel Rosenberg
603*508ec739SDaniel Rosenberg dset[0].dentry.file.create_date = e_date;
604*508ec739SDaniel Rosenberg dset[0].dentry.file.create_time = e_time;
605*508ec739SDaniel Rosenberg dset[0].dentry.file.create_time_ms = e_time_ms;
606*508ec739SDaniel Rosenberg dset[0].dentry.file.create_tz = tz;
607*508ec739SDaniel Rosenberg
608*508ec739SDaniel Rosenberg dset[0].dentry.file.modify_date = e_date;
609*508ec739SDaniel Rosenberg dset[0].dentry.file.modify_time = e_time;
610*508ec739SDaniel Rosenberg dset[0].dentry.file.modify_time_ms = e_time_ms;
611*508ec739SDaniel Rosenberg dset[0].dentry.file.modify_tz = tz;
612*508ec739SDaniel Rosenberg
613*508ec739SDaniel Rosenberg dset[0].dentry.file.access_date = e_date;
614*508ec739SDaniel Rosenberg dset[0].dentry.file.access_time = e_time;
615*508ec739SDaniel Rosenberg dset[0].dentry.file.access_tz = tz;
616*508ec739SDaniel Rosenberg
617*508ec739SDaniel Rosenberg dset[1].type = EXFAT_STREAM;
618*508ec739SDaniel Rosenberg dset[1].dentry.stream.flags = 0x01;
619*508ec739SDaniel Rosenberg dset[1].dentry.stream.name_len = (__u8)name_len;
620*508ec739SDaniel Rosenberg dset[1].dentry.stream.name_hash =
621*508ec739SDaniel Rosenberg cpu_to_le16(exfat_calc_name_hash(exfat, utf16_name, name_len));
622*508ec739SDaniel Rosenberg
623*508ec739SDaniel Rosenberg for (i = 2; i < dcount; i++) {
624*508ec739SDaniel Rosenberg dset[i].type = EXFAT_NAME;
625*508ec739SDaniel Rosenberg memcpy(dset[i].dentry.name.unicode_0_14,
626*508ec739SDaniel Rosenberg utf16_name + (i - 2) * ENTRY_NAME_MAX,
627*508ec739SDaniel Rosenberg ENTRY_NAME_MAX * 2);
628*508ec739SDaniel Rosenberg }
629*508ec739SDaniel Rosenberg
630*508ec739SDaniel Rosenberg dset[0].dentry.file.checksum =
631*508ec739SDaniel Rosenberg cpu_to_le16(calc_dentry_set_checksum(dset, dcount));
632*508ec739SDaniel Rosenberg
633*508ec739SDaniel Rosenberg *dentry_set = dset;
634*508ec739SDaniel Rosenberg *dentry_count = dcount;
635*508ec739SDaniel Rosenberg return 0;
636*508ec739SDaniel Rosenberg }
637*508ec739SDaniel Rosenberg
exfat_update_file_dentry_set(struct exfat * exfat,struct exfat_dentry * dset,int dcount,const char * name,clus_t start_clu,clus_t ccount)638*508ec739SDaniel Rosenberg int exfat_update_file_dentry_set(struct exfat *exfat,
639*508ec739SDaniel Rosenberg struct exfat_dentry *dset, int dcount,
640*508ec739SDaniel Rosenberg const char *name,
641*508ec739SDaniel Rosenberg clus_t start_clu, clus_t ccount)
642*508ec739SDaniel Rosenberg {
643*508ec739SDaniel Rosenberg int i, name_len;
644*508ec739SDaniel Rosenberg __le16 utf16_name[PATH_MAX + 2];
645*508ec739SDaniel Rosenberg
646*508ec739SDaniel Rosenberg if (dset[0].type != EXFAT_FILE || dcount < MIN_FILE_DENTRIES)
647*508ec739SDaniel Rosenberg return -EINVAL;
648*508ec739SDaniel Rosenberg
649*508ec739SDaniel Rosenberg if (name) {
650*508ec739SDaniel Rosenberg name_len = (int)exfat_utf16_enc(name,
651*508ec739SDaniel Rosenberg utf16_name, sizeof(utf16_name));
652*508ec739SDaniel Rosenberg if (name_len < 0)
653*508ec739SDaniel Rosenberg return name_len;
654*508ec739SDaniel Rosenberg
655*508ec739SDaniel Rosenberg name_len /= 2;
656*508ec739SDaniel Rosenberg if (dcount != 2 + DIV_ROUND_UP(name_len, ENTRY_NAME_MAX))
657*508ec739SDaniel Rosenberg return -EINVAL;
658*508ec739SDaniel Rosenberg
659*508ec739SDaniel Rosenberg dset[1].dentry.stream.name_len = (__u8)name_len;
660*508ec739SDaniel Rosenberg dset[1].dentry.stream.name_hash =
661*508ec739SDaniel Rosenberg exfat_calc_name_hash(exfat, utf16_name, name_len);
662*508ec739SDaniel Rosenberg
663*508ec739SDaniel Rosenberg for (i = 2; i < dcount; i++) {
664*508ec739SDaniel Rosenberg dset[i].type = EXFAT_NAME;
665*508ec739SDaniel Rosenberg memcpy(dset[i].dentry.name.unicode_0_14,
666*508ec739SDaniel Rosenberg utf16_name + (i - 2) * ENTRY_NAME_MAX,
667*508ec739SDaniel Rosenberg ENTRY_NAME_MAX * 2);
668*508ec739SDaniel Rosenberg }
669*508ec739SDaniel Rosenberg }
670*508ec739SDaniel Rosenberg
671*508ec739SDaniel Rosenberg dset[1].dentry.stream.valid_size = cpu_to_le64(ccount * exfat->clus_size);
672*508ec739SDaniel Rosenberg dset[1].dentry.stream.size = cpu_to_le64(ccount * exfat->clus_size);
673*508ec739SDaniel Rosenberg if (start_clu)
674*508ec739SDaniel Rosenberg dset[1].dentry.stream.start_clu = cpu_to_le32(start_clu);
675*508ec739SDaniel Rosenberg
676*508ec739SDaniel Rosenberg dset[0].dentry.file.checksum =
677*508ec739SDaniel Rosenberg cpu_to_le16(calc_dentry_set_checksum(dset, dcount));
678*508ec739SDaniel Rosenberg return 0;
679*508ec739SDaniel Rosenberg }
680*508ec739SDaniel Rosenberg
exfat_find_free_cluster(struct exfat * exfat,clus_t start,clus_t * new_clu)681*508ec739SDaniel Rosenberg int exfat_find_free_cluster(struct exfat *exfat,
682*508ec739SDaniel Rosenberg clus_t start, clus_t *new_clu)
683*508ec739SDaniel Rosenberg {
684*508ec739SDaniel Rosenberg clus_t end = le32_to_cpu(exfat->bs->bsx.clu_count) +
685*508ec739SDaniel Rosenberg EXFAT_FIRST_CLUSTER;
686*508ec739SDaniel Rosenberg
687*508ec739SDaniel Rosenberg if (!exfat_heap_clus(exfat, start))
688*508ec739SDaniel Rosenberg return -EINVAL;
689*508ec739SDaniel Rosenberg
690*508ec739SDaniel Rosenberg while (start < end) {
691*508ec739SDaniel Rosenberg if (exfat_bitmap_find_zero(exfat, exfat->alloc_bitmap,
692*508ec739SDaniel Rosenberg start, new_clu))
693*508ec739SDaniel Rosenberg break;
694*508ec739SDaniel Rosenberg if (!exfat_bitmap_get(exfat->disk_bitmap, *new_clu))
695*508ec739SDaniel Rosenberg return 0;
696*508ec739SDaniel Rosenberg start = *new_clu + 1;
697*508ec739SDaniel Rosenberg }
698*508ec739SDaniel Rosenberg
699*508ec739SDaniel Rosenberg end = start;
700*508ec739SDaniel Rosenberg start = EXFAT_FIRST_CLUSTER;
701*508ec739SDaniel Rosenberg while (start < end) {
702*508ec739SDaniel Rosenberg if (exfat_bitmap_find_zero(exfat, exfat->alloc_bitmap,
703*508ec739SDaniel Rosenberg start, new_clu))
704*508ec739SDaniel Rosenberg goto out_nospc;
705*508ec739SDaniel Rosenberg if (!exfat_bitmap_get(exfat->disk_bitmap, *new_clu))
706*508ec739SDaniel Rosenberg return 0;
707*508ec739SDaniel Rosenberg start = *new_clu + 1;
708*508ec739SDaniel Rosenberg }
709*508ec739SDaniel Rosenberg
710*508ec739SDaniel Rosenberg out_nospc:
711*508ec739SDaniel Rosenberg *new_clu = EXFAT_EOF_CLUSTER;
712*508ec739SDaniel Rosenberg return -ENOSPC;
713*508ec739SDaniel Rosenberg }
714*508ec739SDaniel Rosenberg
exfat_map_cluster(struct exfat * exfat,struct exfat_inode * inode,off_t file_off,clus_t * mapped_clu)715*508ec739SDaniel Rosenberg static int exfat_map_cluster(struct exfat *exfat, struct exfat_inode *inode,
716*508ec739SDaniel Rosenberg off_t file_off, clus_t *mapped_clu)
717*508ec739SDaniel Rosenberg {
718*508ec739SDaniel Rosenberg clus_t clu, next, count, last_count;
719*508ec739SDaniel Rosenberg
720*508ec739SDaniel Rosenberg if (!exfat_heap_clus(exfat, inode->first_clus))
721*508ec739SDaniel Rosenberg return -EINVAL;
722*508ec739SDaniel Rosenberg
723*508ec739SDaniel Rosenberg clu = inode->first_clus;
724*508ec739SDaniel Rosenberg next = EXFAT_EOF_CLUSTER;
725*508ec739SDaniel Rosenberg count = 1;
726*508ec739SDaniel Rosenberg if (file_off == EOF)
727*508ec739SDaniel Rosenberg last_count = DIV_ROUND_UP(inode->size, exfat->clus_size);
728*508ec739SDaniel Rosenberg else
729*508ec739SDaniel Rosenberg last_count = file_off / exfat->clus_size + 1;
730*508ec739SDaniel Rosenberg
731*508ec739SDaniel Rosenberg while (true) {
732*508ec739SDaniel Rosenberg if (count * exfat->clus_size > inode->size)
733*508ec739SDaniel Rosenberg return -EINVAL;
734*508ec739SDaniel Rosenberg
735*508ec739SDaniel Rosenberg if (count == last_count) {
736*508ec739SDaniel Rosenberg *mapped_clu = clu;
737*508ec739SDaniel Rosenberg return 0;
738*508ec739SDaniel Rosenberg }
739*508ec739SDaniel Rosenberg
740*508ec739SDaniel Rosenberg if (exfat_get_inode_next_clus(exfat, inode, clu, &next))
741*508ec739SDaniel Rosenberg return -EINVAL;
742*508ec739SDaniel Rosenberg
743*508ec739SDaniel Rosenberg if (!exfat_heap_clus(exfat, clu))
744*508ec739SDaniel Rosenberg return -EINVAL;
745*508ec739SDaniel Rosenberg
746*508ec739SDaniel Rosenberg clu = next;
747*508ec739SDaniel Rosenberg count++;
748*508ec739SDaniel Rosenberg }
749*508ec739SDaniel Rosenberg return -EINVAL;
750*508ec739SDaniel Rosenberg }
751*508ec739SDaniel Rosenberg
exfat_write_dentry_set(struct exfat * exfat,struct exfat_dentry * dset,int dcount,off_t dev_off,off_t * next_dev_off)752*508ec739SDaniel Rosenberg static int exfat_write_dentry_set(struct exfat *exfat,
753*508ec739SDaniel Rosenberg struct exfat_dentry *dset, int dcount,
754*508ec739SDaniel Rosenberg off_t dev_off, off_t *next_dev_off)
755*508ec739SDaniel Rosenberg {
756*508ec739SDaniel Rosenberg clus_t clus;
757*508ec739SDaniel Rosenberg unsigned int clus_off, dent_len, first_half_len, sec_half_len;
758*508ec739SDaniel Rosenberg off_t first_half_off, sec_half_off = 0;
759*508ec739SDaniel Rosenberg
760*508ec739SDaniel Rosenberg if (exfat_o2c(exfat, dev_off, &clus, &clus_off))
761*508ec739SDaniel Rosenberg return -ERANGE;
762*508ec739SDaniel Rosenberg
763*508ec739SDaniel Rosenberg dent_len = dcount * DENTRY_SIZE;
764*508ec739SDaniel Rosenberg first_half_len = MIN(dent_len, exfat->clus_size - clus_off);
765*508ec739SDaniel Rosenberg sec_half_len = dent_len - first_half_len;
766*508ec739SDaniel Rosenberg
767*508ec739SDaniel Rosenberg first_half_off = dev_off;
768*508ec739SDaniel Rosenberg if (sec_half_len) {
769*508ec739SDaniel Rosenberg clus_t next_clus;
770*508ec739SDaniel Rosenberg
771*508ec739SDaniel Rosenberg if (exfat_get_next_clus(exfat, clus, &next_clus))
772*508ec739SDaniel Rosenberg return -EIO;
773*508ec739SDaniel Rosenberg if (!exfat_heap_clus(exfat, next_clus))
774*508ec739SDaniel Rosenberg return -EINVAL;
775*508ec739SDaniel Rosenberg sec_half_off = exfat_c2o(exfat, next_clus);
776*508ec739SDaniel Rosenberg }
777*508ec739SDaniel Rosenberg
778*508ec739SDaniel Rosenberg if (exfat_write(exfat->blk_dev->dev_fd, dset, first_half_len,
779*508ec739SDaniel Rosenberg first_half_off) != (ssize_t)first_half_len)
780*508ec739SDaniel Rosenberg return -EIO;
781*508ec739SDaniel Rosenberg
782*508ec739SDaniel Rosenberg if (sec_half_len) {
783*508ec739SDaniel Rosenberg dset = (struct exfat_dentry *)((char *)dset + first_half_len);
784*508ec739SDaniel Rosenberg if (exfat_write(exfat->blk_dev->dev_fd, dset, sec_half_len,
785*508ec739SDaniel Rosenberg sec_half_off) != (ssize_t)sec_half_len)
786*508ec739SDaniel Rosenberg return -EIO;
787*508ec739SDaniel Rosenberg }
788*508ec739SDaniel Rosenberg
789*508ec739SDaniel Rosenberg if (next_dev_off) {
790*508ec739SDaniel Rosenberg if (sec_half_len)
791*508ec739SDaniel Rosenberg *next_dev_off = sec_half_off + sec_half_len;
792*508ec739SDaniel Rosenberg else
793*508ec739SDaniel Rosenberg *next_dev_off = first_half_off + first_half_len;
794*508ec739SDaniel Rosenberg }
795*508ec739SDaniel Rosenberg return 0;
796*508ec739SDaniel Rosenberg }
797*508ec739SDaniel Rosenberg
exfat_alloc_cluster(struct exfat * exfat,struct exfat_inode * inode,clus_t * new_clu)798*508ec739SDaniel Rosenberg static int exfat_alloc_cluster(struct exfat *exfat, struct exfat_inode *inode,
799*508ec739SDaniel Rosenberg clus_t *new_clu)
800*508ec739SDaniel Rosenberg {
801*508ec739SDaniel Rosenberg clus_t last_clu;
802*508ec739SDaniel Rosenberg int err;
803*508ec739SDaniel Rosenberg bool need_dset = inode != exfat->root;
804*508ec739SDaniel Rosenberg
805*508ec739SDaniel Rosenberg if ((need_dset && !inode->dentry_set) || inode->is_contiguous)
806*508ec739SDaniel Rosenberg return -EINVAL;
807*508ec739SDaniel Rosenberg
808*508ec739SDaniel Rosenberg err = exfat_find_free_cluster(exfat, exfat->start_clu, new_clu);
809*508ec739SDaniel Rosenberg if (err) {
810*508ec739SDaniel Rosenberg exfat->start_clu = EXFAT_FIRST_CLUSTER;
811*508ec739SDaniel Rosenberg exfat_err("failed to find an free cluster\n");
812*508ec739SDaniel Rosenberg return -ENOSPC;
813*508ec739SDaniel Rosenberg }
814*508ec739SDaniel Rosenberg exfat->start_clu = *new_clu;
815*508ec739SDaniel Rosenberg
816*508ec739SDaniel Rosenberg if (exfat_set_fat(exfat, *new_clu, EXFAT_EOF_CLUSTER))
817*508ec739SDaniel Rosenberg return -EIO;
818*508ec739SDaniel Rosenberg
819*508ec739SDaniel Rosenberg /* zero out the new cluster */
820*508ec739SDaniel Rosenberg if (exfat_write(exfat->blk_dev->dev_fd, exfat->zero_cluster,
821*508ec739SDaniel Rosenberg exfat->clus_size, exfat_c2o(exfat, *new_clu)) !=
822*508ec739SDaniel Rosenberg (ssize_t)exfat->clus_size) {
823*508ec739SDaniel Rosenberg exfat_err("failed to fill new cluster with zeroes\n");
824*508ec739SDaniel Rosenberg return -EIO;
825*508ec739SDaniel Rosenberg }
826*508ec739SDaniel Rosenberg
827*508ec739SDaniel Rosenberg if (inode->size) {
828*508ec739SDaniel Rosenberg err = exfat_map_cluster(exfat, inode, EOF, &last_clu);
829*508ec739SDaniel Rosenberg if (err) {
830*508ec739SDaniel Rosenberg exfat_err("failed to get the last cluster\n");
831*508ec739SDaniel Rosenberg return err;
832*508ec739SDaniel Rosenberg }
833*508ec739SDaniel Rosenberg
834*508ec739SDaniel Rosenberg if (exfat_set_fat(exfat, last_clu, *new_clu))
835*508ec739SDaniel Rosenberg return -EIO;
836*508ec739SDaniel Rosenberg
837*508ec739SDaniel Rosenberg if (need_dset) {
838*508ec739SDaniel Rosenberg err = exfat_update_file_dentry_set(exfat,
839*508ec739SDaniel Rosenberg inode->dentry_set,
840*508ec739SDaniel Rosenberg inode->dentry_count,
841*508ec739SDaniel Rosenberg NULL, 0,
842*508ec739SDaniel Rosenberg DIV_ROUND_UP(inode->size,
843*508ec739SDaniel Rosenberg exfat->clus_size) + 1);
844*508ec739SDaniel Rosenberg if (err)
845*508ec739SDaniel Rosenberg return -EINVAL;
846*508ec739SDaniel Rosenberg }
847*508ec739SDaniel Rosenberg } else {
848*508ec739SDaniel Rosenberg if (need_dset) {
849*508ec739SDaniel Rosenberg err = exfat_update_file_dentry_set(exfat,
850*508ec739SDaniel Rosenberg inode->dentry_set,
851*508ec739SDaniel Rosenberg inode->dentry_count,
852*508ec739SDaniel Rosenberg NULL, *new_clu, 1);
853*508ec739SDaniel Rosenberg if (err)
854*508ec739SDaniel Rosenberg return -EINVAL;
855*508ec739SDaniel Rosenberg }
856*508ec739SDaniel Rosenberg }
857*508ec739SDaniel Rosenberg
858*508ec739SDaniel Rosenberg if (need_dset && exfat_write_dentry_set(exfat, inode->dentry_set,
859*508ec739SDaniel Rosenberg inode->dentry_count,
860*508ec739SDaniel Rosenberg inode->dev_offset, NULL))
861*508ec739SDaniel Rosenberg return -EIO;
862*508ec739SDaniel Rosenberg
863*508ec739SDaniel Rosenberg exfat_bitmap_set(exfat->alloc_bitmap, *new_clu);
864*508ec739SDaniel Rosenberg if (inode->size == 0)
865*508ec739SDaniel Rosenberg inode->first_clus = *new_clu;
866*508ec739SDaniel Rosenberg inode->size += exfat->clus_size;
867*508ec739SDaniel Rosenberg return 0;
868*508ec739SDaniel Rosenberg }
869*508ec739SDaniel Rosenberg
exfat_add_dentry_set(struct exfat * exfat,struct exfat_dentry_loc * loc,struct exfat_dentry * dset,int dcount,bool need_next_loc)870*508ec739SDaniel Rosenberg int exfat_add_dentry_set(struct exfat *exfat, struct exfat_dentry_loc *loc,
871*508ec739SDaniel Rosenberg struct exfat_dentry *dset, int dcount,
872*508ec739SDaniel Rosenberg bool need_next_loc)
873*508ec739SDaniel Rosenberg {
874*508ec739SDaniel Rosenberg struct exfat_inode *parent = loc->parent;
875*508ec739SDaniel Rosenberg off_t dev_off, next_dev_off;
876*508ec739SDaniel Rosenberg
877*508ec739SDaniel Rosenberg if (parent->is_contiguous ||
878*508ec739SDaniel Rosenberg (uint64_t)loc->file_offset > parent->size ||
879*508ec739SDaniel Rosenberg (unsigned int)dcount * DENTRY_SIZE > exfat->clus_size)
880*508ec739SDaniel Rosenberg return -EINVAL;
881*508ec739SDaniel Rosenberg
882*508ec739SDaniel Rosenberg dev_off = loc->dev_offset;
883*508ec739SDaniel Rosenberg if ((uint64_t)loc->file_offset + dcount * DENTRY_SIZE > parent->size) {
884*508ec739SDaniel Rosenberg clus_t new_clus;
885*508ec739SDaniel Rosenberg
886*508ec739SDaniel Rosenberg if (exfat_alloc_cluster(exfat, parent, &new_clus))
887*508ec739SDaniel Rosenberg return -EIO;
888*508ec739SDaniel Rosenberg if ((uint64_t)loc->file_offset == parent->size - exfat->clus_size)
889*508ec739SDaniel Rosenberg dev_off = exfat_c2o(exfat, new_clus);
890*508ec739SDaniel Rosenberg }
891*508ec739SDaniel Rosenberg
892*508ec739SDaniel Rosenberg if (exfat_write_dentry_set(exfat, dset, dcount, dev_off, &next_dev_off))
893*508ec739SDaniel Rosenberg return -EIO;
894*508ec739SDaniel Rosenberg
895*508ec739SDaniel Rosenberg if (need_next_loc) {
896*508ec739SDaniel Rosenberg loc->file_offset += dcount * DENTRY_SIZE;
897*508ec739SDaniel Rosenberg loc->dev_offset = next_dev_off;
898*508ec739SDaniel Rosenberg }
899*508ec739SDaniel Rosenberg return 0;
900*508ec739SDaniel Rosenberg }
901*508ec739SDaniel Rosenberg
exfat_create_file(struct exfat * exfat,struct exfat_inode * parent,const char * name,unsigned short attr)902*508ec739SDaniel Rosenberg int exfat_create_file(struct exfat *exfat, struct exfat_inode *parent,
903*508ec739SDaniel Rosenberg const char *name, unsigned short attr)
904*508ec739SDaniel Rosenberg {
905*508ec739SDaniel Rosenberg struct exfat_dentry *dset;
906*508ec739SDaniel Rosenberg int err, dcount;
907*508ec739SDaniel Rosenberg struct exfat_lookup_filter filter;
908*508ec739SDaniel Rosenberg struct exfat_dentry_loc loc;
909*508ec739SDaniel Rosenberg
910*508ec739SDaniel Rosenberg err = exfat_lookup_file(exfat, parent, name, &filter);
911*508ec739SDaniel Rosenberg if (err == 0) {
912*508ec739SDaniel Rosenberg dset = filter.out.dentry_set;
913*508ec739SDaniel Rosenberg dcount = filter.out.dentry_count;
914*508ec739SDaniel Rosenberg if ((le16_to_cpu(dset->dentry.file.attr) & attr) != attr)
915*508ec739SDaniel Rosenberg err = -EEXIST;
916*508ec739SDaniel Rosenberg goto out;
917*508ec739SDaniel Rosenberg }
918*508ec739SDaniel Rosenberg
919*508ec739SDaniel Rosenberg err = exfat_build_file_dentry_set(exfat, name, attr,
920*508ec739SDaniel Rosenberg &dset, &dcount);
921*508ec739SDaniel Rosenberg if (err)
922*508ec739SDaniel Rosenberg return err;
923*508ec739SDaniel Rosenberg
924*508ec739SDaniel Rosenberg loc.parent = parent;
925*508ec739SDaniel Rosenberg loc.file_offset = filter.out.file_offset;
926*508ec739SDaniel Rosenberg loc.dev_offset = filter.out.dev_offset;
927*508ec739SDaniel Rosenberg err = exfat_add_dentry_set(exfat, &loc, dset, dcount, false);
928*508ec739SDaniel Rosenberg out:
929*508ec739SDaniel Rosenberg free(dset);
930*508ec739SDaniel Rosenberg return err;
931*508ec739SDaniel Rosenberg }
932