1 |
|
|
/* $OpenBSD: msdosfs_lookup.c,v 1.3 2017/08/31 12:03:02 otto Exp $ */ |
2 |
|
|
/* $NetBSD: msdosfs_lookup.c,v 1.35 2016/01/30 09:59:27 mlelstv Exp $ */ |
3 |
|
|
|
4 |
|
|
/*- |
5 |
|
|
* Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. |
6 |
|
|
* Copyright (C) 1994, 1995, 1997 TooLs GmbH. |
7 |
|
|
* All rights reserved. |
8 |
|
|
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). |
9 |
|
|
* |
10 |
|
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
|
* modification, are permitted provided that the following conditions |
12 |
|
|
* are met: |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
|
* documentation and/or other materials provided with the distribution. |
18 |
|
|
* 3. All advertising materials mentioning features or use of this software |
19 |
|
|
* must display the following acknowledgement: |
20 |
|
|
* This product includes software developed by TooLs GmbH. |
21 |
|
|
* 4. The name of TooLs GmbH may not be used to endorse or promote products |
22 |
|
|
* derived from this software without specific prior written permission. |
23 |
|
|
* |
24 |
|
|
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR |
25 |
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
26 |
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
27 |
|
|
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
28 |
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
29 |
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
30 |
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
31 |
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
32 |
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
33 |
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
34 |
|
|
*/ |
35 |
|
|
/* |
36 |
|
|
* Written by Paul Popelka (paulp@uts.amdahl.com) |
37 |
|
|
* |
38 |
|
|
* You can do anything you want with this software, just don't say you wrote |
39 |
|
|
* it, and don't remove this notice. |
40 |
|
|
* |
41 |
|
|
* This software is provided "as is". |
42 |
|
|
* |
43 |
|
|
* The author supplies this software to be publicly redistributed on the |
44 |
|
|
* understanding that the author is not responsible for the correct |
45 |
|
|
* functioning of this software in any circumstances and is not liable for |
46 |
|
|
* any damages caused by this software. |
47 |
|
|
* |
48 |
|
|
* October 1992 |
49 |
|
|
*/ |
50 |
|
|
|
51 |
|
|
#include <sys/param.h> |
52 |
|
|
|
53 |
|
|
#include "ffs/buf.h" |
54 |
|
|
|
55 |
|
|
#include <msdosfs/bpb.h> |
56 |
|
|
#include "msdos/direntry.h" |
57 |
|
|
#include "msdos/denode.h" |
58 |
|
|
#include "msdos/msdosfsmount.h" |
59 |
|
|
#include "msdos/fat.h" |
60 |
|
|
|
61 |
|
|
|
62 |
|
|
|
63 |
|
|
/* |
64 |
|
|
* dep - directory entry to copy into the directory |
65 |
|
|
* ddep - directory to add to |
66 |
|
|
* depp - return the address of the denode for the created directory entry |
67 |
|
|
* if depp != 0 |
68 |
|
|
* cnp - componentname needed for Win95 long filenames |
69 |
|
|
*/ |
70 |
|
|
int |
71 |
|
|
createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp) |
72 |
|
|
{ |
73 |
|
|
int error, rberror; |
74 |
|
|
u_long dirclust, clusoffset; |
75 |
|
|
u_long fndoffset, havecnt = 0, wcnt = 1, i; |
76 |
|
|
struct direntry *ndep; |
77 |
|
|
struct msdosfsmount *pmp = ddep->de_pmp; |
78 |
|
|
struct mkfsbuf *bp; |
79 |
|
|
daddr_t bn; |
80 |
|
|
int blsize; |
81 |
|
|
#define async 0 |
82 |
|
|
|
83 |
|
|
#ifdef MSDOSFS_DEBUG |
84 |
|
|
printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n", |
85 |
|
|
dep, ddep, depp, cnp); |
86 |
|
|
#endif |
87 |
|
|
|
88 |
|
|
/* |
89 |
|
|
* If no space left in the directory then allocate another cluster |
90 |
|
|
* and chain it onto the end of the file. There is one exception |
91 |
|
|
* to this. That is, if the root directory has no more space it |
92 |
|
|
* can NOT be expanded. extendfile() checks for and fails attempts |
93 |
|
|
* to extend the root directory. We just return an error in that |
94 |
|
|
* case. |
95 |
|
|
*/ |
96 |
|
|
if (ddep->de_fndoffset >= ddep->de_FileSize) { |
97 |
|
|
u_long needlen = ddep->de_fndoffset + sizeof(struct direntry) |
98 |
|
|
- ddep->de_FileSize; |
99 |
|
|
dirclust = de_clcount(pmp, needlen); |
100 |
|
|
if ((error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR)) != 0) { |
101 |
|
|
(void)detrunc(ddep, ddep->de_FileSize, 0); |
102 |
|
|
goto err_norollback; |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
/* |
106 |
|
|
* Update the size of the directory |
107 |
|
|
*/ |
108 |
|
|
ddep->de_FileSize += de_cn2off(pmp, dirclust); |
109 |
|
|
} |
110 |
|
|
|
111 |
|
|
/* |
112 |
|
|
* We just read in the cluster with space. Copy the new directory |
113 |
|
|
* entry in. Then write it to disk. NOTE: DOS directories |
114 |
|
|
* do not get smaller as clusters are emptied. |
115 |
|
|
*/ |
116 |
|
|
error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), |
117 |
|
|
&bn, &dirclust, &blsize); |
118 |
|
|
if (error) |
119 |
|
|
goto err_norollback; |
120 |
|
|
clusoffset = ddep->de_fndoffset; |
121 |
|
|
if (dirclust != MSDOSFSROOT) |
122 |
|
|
clusoffset &= pmp->pm_crbomask; |
123 |
|
|
if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, |
124 |
|
|
B_MODIFY, &bp)) != 0) { |
125 |
|
|
goto err_norollback; |
126 |
|
|
} |
127 |
|
|
ndep = bptoep(pmp, bp, clusoffset); |
128 |
|
|
|
129 |
|
|
DE_EXTERNALIZE(ndep, dep); |
130 |
|
|
|
131 |
|
|
/* |
132 |
|
|
* Now write the Win95 long name |
133 |
|
|
*/ |
134 |
|
|
if (ddep->de_fndcnt > 0) { |
135 |
|
|
u_int8_t chksum = winChksum(ndep->deName); |
136 |
|
|
u_char *un = cnp->cn_nameptr; |
137 |
|
|
int unlen = cnp->cn_namelen; |
138 |
|
|
u_long xhavecnt; |
139 |
|
|
|
140 |
|
|
fndoffset = ddep->de_fndoffset; |
141 |
|
|
xhavecnt = ddep->de_fndcnt + 1; |
142 |
|
|
|
143 |
|
|
for(; wcnt < xhavecnt; wcnt++) { |
144 |
|
|
if ((fndoffset & pmp->pm_crbomask) == 0) { |
145 |
|
|
/* we should never get here if ddep is root |
146 |
|
|
* directory */ |
147 |
|
|
|
148 |
|
|
if (async) |
149 |
|
|
(void) bdwrite(bp); |
150 |
|
|
else if ((error = bwrite(bp)) != 0) |
151 |
|
|
goto rollback; |
152 |
|
|
|
153 |
|
|
fndoffset -= sizeof(struct direntry); |
154 |
|
|
error = pcbmap(ddep, |
155 |
|
|
de_cluster(pmp, fndoffset), |
156 |
|
|
&bn, 0, &blsize); |
157 |
|
|
if (error) |
158 |
|
|
goto rollback; |
159 |
|
|
|
160 |
|
|
error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), |
161 |
|
|
blsize, B_MODIFY, &bp); |
162 |
|
|
if (error) { |
163 |
|
|
goto rollback; |
164 |
|
|
} |
165 |
|
|
ndep = bptoep(pmp, bp, |
166 |
|
|
fndoffset & pmp->pm_crbomask); |
167 |
|
|
} else { |
168 |
|
|
ndep--; |
169 |
|
|
fndoffset -= sizeof(struct direntry); |
170 |
|
|
} |
171 |
|
|
if (!unix2winfn(un, unlen, (struct winentry *)ndep, |
172 |
|
|
wcnt, chksum)) |
173 |
|
|
break; |
174 |
|
|
} |
175 |
|
|
} |
176 |
|
|
|
177 |
|
|
if (async) |
178 |
|
|
bdwrite(bp); |
179 |
|
|
else if ((error = bwrite(bp)) != 0) |
180 |
|
|
goto rollback; |
181 |
|
|
|
182 |
|
|
/* |
183 |
|
|
* If they want us to return with the denode gotten. |
184 |
|
|
*/ |
185 |
|
|
if (depp) { |
186 |
|
|
u_long diroffset = clusoffset; |
187 |
|
|
|
188 |
|
|
if (dep->de_Attributes & ATTR_DIRECTORY) { |
189 |
|
|
dirclust = dep->de_StartCluster; |
190 |
|
|
if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) |
191 |
|
|
dirclust = MSDOSFSROOT; |
192 |
|
|
if (dirclust == MSDOSFSROOT) |
193 |
|
|
diroffset = MSDOSFSROOT_OFS; |
194 |
|
|
else |
195 |
|
|
diroffset = 0; |
196 |
|
|
} |
197 |
|
|
error = deget(pmp, dirclust, diroffset, depp); |
198 |
|
|
return error; |
199 |
|
|
} |
200 |
|
|
|
201 |
|
|
return 0; |
202 |
|
|
|
203 |
|
|
rollback: |
204 |
|
|
/* |
205 |
|
|
* Mark all slots modified so far as deleted. Note that we |
206 |
|
|
* can't just call removede(), since directory is not in |
207 |
|
|
* consistent state. |
208 |
|
|
*/ |
209 |
|
|
fndoffset = ddep->de_fndoffset; |
210 |
|
|
rberror = pcbmap(ddep, de_cluster(pmp, fndoffset), |
211 |
|
|
&bn, NULL, &blsize); |
212 |
|
|
if (rberror) |
213 |
|
|
goto err_norollback; |
214 |
|
|
if ((rberror = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, |
215 |
|
|
B_MODIFY, &bp)) != 0) { |
216 |
|
|
goto err_norollback; |
217 |
|
|
} |
218 |
|
|
ndep = bptoep(pmp, bp, clusoffset); |
219 |
|
|
|
220 |
|
|
havecnt = ddep->de_fndcnt + 1; |
221 |
|
|
for(i = wcnt; i <= havecnt; i++) { |
222 |
|
|
/* mark entry as deleted */ |
223 |
|
|
ndep->deName[0] = SLOT_DELETED; |
224 |
|
|
|
225 |
|
|
if ((fndoffset & pmp->pm_crbomask) == 0) { |
226 |
|
|
/* we should never get here if ddep is root |
227 |
|
|
* directory */ |
228 |
|
|
|
229 |
|
|
if (async) |
230 |
|
|
bdwrite(bp); |
231 |
|
|
else if ((rberror = bwrite(bp)) != 0) |
232 |
|
|
goto err_norollback; |
233 |
|
|
|
234 |
|
|
fndoffset -= sizeof(struct direntry); |
235 |
|
|
rberror = pcbmap(ddep, |
236 |
|
|
de_cluster(pmp, fndoffset), |
237 |
|
|
&bn, 0, &blsize); |
238 |
|
|
if (rberror) |
239 |
|
|
goto err_norollback; |
240 |
|
|
|
241 |
|
|
rberror = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), |
242 |
|
|
blsize, B_MODIFY, &bp); |
243 |
|
|
if (rberror) { |
244 |
|
|
goto err_norollback; |
245 |
|
|
} |
246 |
|
|
ndep = bptoep(pmp, bp, fndoffset); |
247 |
|
|
} else { |
248 |
|
|
ndep--; |
249 |
|
|
fndoffset -= sizeof(struct direntry); |
250 |
|
|
} |
251 |
|
|
} |
252 |
|
|
|
253 |
|
|
/* ignore any further error */ |
254 |
|
|
if (async) |
255 |
|
|
(void) bdwrite(bp); |
256 |
|
|
else |
257 |
|
|
(void) bwrite(bp); |
258 |
|
|
|
259 |
|
|
err_norollback: |
260 |
|
|
return error; |
261 |
|
|
} |
262 |
|
|
|
263 |
|
|
/* |
264 |
|
|
* Read in the disk block containing the directory entry (dirclu, dirofs) |
265 |
|
|
* and return the address of the buf header, and the address of the |
266 |
|
|
* directory entry within the block. |
267 |
|
|
*/ |
268 |
|
|
int |
269 |
|
|
readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct mkfsbuf **bpp, struct direntry **epp) |
270 |
|
|
{ |
271 |
|
|
int error; |
272 |
|
|
daddr_t bn; |
273 |
|
|
int blsize; |
274 |
|
|
|
275 |
|
|
blsize = pmp->pm_bpcluster; |
276 |
|
|
if (dirclust == MSDOSFSROOT |
277 |
|
|
&& de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) |
278 |
|
|
blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; |
279 |
|
|
bn = detobn(pmp, dirclust, diroffset); |
280 |
|
|
if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, |
281 |
|
|
0, bpp)) != 0) { |
282 |
|
|
*bpp = NULL; |
283 |
|
|
return (error); |
284 |
|
|
} |
285 |
|
|
if (epp) |
286 |
|
|
*epp = bptoep(pmp, *bpp, diroffset); |
287 |
|
|
return (0); |
288 |
|
|
} |
289 |
|
|
|
290 |
|
|
/* |
291 |
|
|
* Read in the disk block containing the directory entry dep came from and |
292 |
|
|
* return the address of the buf header, and the address of the directory |
293 |
|
|
* entry within the block. |
294 |
|
|
*/ |
295 |
|
|
int |
296 |
|
|
readde(struct denode *dep, struct mkfsbuf **bpp, struct direntry **epp) |
297 |
|
|
{ |
298 |
|
|
return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, |
299 |
|
|
bpp, epp)); |
300 |
|
|
} |
301 |
|
|
|
302 |
|
|
/* |
303 |
|
|
* Create a unique DOS name in dvp |
304 |
|
|
*/ |
305 |
|
|
int |
306 |
|
|
uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp) |
307 |
|
|
{ |
308 |
|
|
struct msdosfsmount *pmp = dep->de_pmp; |
309 |
|
|
struct direntry *dentp; |
310 |
|
|
int gen; |
311 |
|
|
int blsize; |
312 |
|
|
u_long cn; |
313 |
|
|
daddr_t bn; |
314 |
|
|
struct mkfsbuf *bp; |
315 |
|
|
int error; |
316 |
|
|
|
317 |
|
|
for (gen = 1;; gen++) { |
318 |
|
|
/* |
319 |
|
|
* Generate DOS name with generation number |
320 |
|
|
*/ |
321 |
|
|
if (!unix2dosfn(cnp->cn_nameptr, cp, cnp->cn_namelen, gen)) |
322 |
|
|
return gen == 1 ? EINVAL : EEXIST; |
323 |
|
|
|
324 |
|
|
/* |
325 |
|
|
* Now look for a dir entry with this exact name |
326 |
|
|
*/ |
327 |
|
|
for (cn = error = 0; !error; cn++) { |
328 |
|
|
if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { |
329 |
|
|
if (error == E2BIG) /* EOF reached and not found */ |
330 |
|
|
return 0; |
331 |
|
|
return error; |
332 |
|
|
} |
333 |
|
|
error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, |
334 |
|
|
0, &bp); |
335 |
|
|
if (error) { |
336 |
|
|
return error; |
337 |
|
|
} |
338 |
|
|
for (dentp = (struct direntry *)bp->b_data; |
339 |
|
|
(char *)dentp < (char *)bp->b_data + blsize; |
340 |
|
|
dentp++) { |
341 |
|
|
if (dentp->deName[0] == SLOT_EMPTY) { |
342 |
|
|
/* |
343 |
|
|
* Last used entry and not found |
344 |
|
|
*/ |
345 |
|
|
brelse(bp, 0); |
346 |
|
|
return 0; |
347 |
|
|
} |
348 |
|
|
/* |
349 |
|
|
* Ignore volume labels and Win95 entries |
350 |
|
|
*/ |
351 |
|
|
if (dentp->deAttributes & ATTR_VOLUME) |
352 |
|
|
continue; |
353 |
|
|
if (!memcmp(dentp->deName, cp, 11)) { |
354 |
|
|
error = EEXIST; |
355 |
|
|
break; |
356 |
|
|
} |
357 |
|
|
} |
358 |
|
|
brelse(bp, 0); |
359 |
|
|
} |
360 |
|
|
} |
361 |
|
|
} |