This source file includes following definitions.
- msdos_format_name
- msdos_find
- msdos_lookup
- msdos_create_entry
- msdos_create
- dump_fat
- msdos_mkdir
- msdos_rmdir
- msdos_unlink
- rename_same_dir
- rename_diff_dir
- msdos_rename
1
2
3
4
5
6
7 #include <asm/segment.h>
8
9 #include <linux/sched.h>
10 #include <linux/msdos_fs.h>
11 #include <linux/kernel.h>
12 #include <linux/errno.h>
13 #include <linux/string.h>
14 #include <linux/stat.h>
15
16
17
18 static char *reserved_names[] = {
19 "CON ","PRN ","NUL ","AUX ",
20 "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
21 "COM1 ","COM2 ","COM3 ","COM4 ",
22 NULL };
23
24
25
26
27 static char bad_chars[] = "*?<>|\"";
28 static char bad_if_strict[] = "+=,; ";
29
30
31
32
33 static int msdos_format_name(char conv,const char *name,int len,char *res,
34 int dot_dirs)
35 {
36 char *walk,**reserved;
37 char c;
38 int space;
39
40 if (IS_FREE(name)) return -EINVAL;
41 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
42 if (!dot_dirs) return -EEXIST;
43 memset(res+1,' ',10);
44 while (len--) *res++ = '.';
45 return 0;
46 }
47 space = 1;
48 c = 0;
49 for (walk = res; len && walk-res < 8; walk++) {
50 c = *name++;
51 len--;
52 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
53 if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
54 if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
55 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
56 if (c == '.') break;
57 space = c == ' ';
58 *walk = c >= 'a' && c <= 'z' ? c-32 : c;
59 }
60 if (space) return -EINVAL;
61 if (conv == 's' && len && c != '.') {
62 c = *name++;
63 len--;
64 if (c != '.') return -EINVAL;
65 }
66 while (c != '.' && len--) c = *name++;
67 if (c == '.') {
68 while (walk-res < 8) *walk++ = ' ';
69 while (len > 0 && walk-res < MSDOS_NAME) {
70 c = *name++;
71 len--;
72 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
73 if (conv == 's' && strchr(bad_if_strict,c))
74 return -EINVAL;
75 if (c < ' ' || c == ':' || c == '\\' || c == '.')
76 return -EINVAL;
77 if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
78 space = c == ' ';
79 *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
80 }
81 if (space) return -EINVAL;
82 if (conv == 's' && len) return -EINVAL;
83 }
84 while (walk-res < MSDOS_NAME) *walk++ = ' ';
85 for (reserved = reserved_names; *reserved; reserved++)
86 if (!strncmp(res,*reserved,8)) return -EINVAL;
87 return 0;
88 }
89
90
91
92
93 static int msdos_find(struct inode *dir,const char *name,int len,
94 struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
95 {
96 char msdos_name[MSDOS_NAME];
97 int res;
98
99 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
100 msdos_name,1)) < 0) return res;
101 return msdos_scan(dir,msdos_name,bh,de,ino);
102 }
103
104
105 int msdos_lookup(struct inode *dir,const char *name,int len,
106 struct inode **result)
107 {
108 int ino,res;
109 struct msdos_dir_entry *de;
110 struct buffer_head *bh;
111 struct inode *next;
112
113 *result = NULL;
114 if (!dir) return -ENOENT;
115 if (!S_ISDIR(dir->i_mode)) {
116 iput(dir);
117 return -ENOENT;
118 }
119 if (len == 1 && name[0] == '.') {
120 *result = dir;
121 return 0;
122 }
123 if (len == 2 && name[0] == '.' && name[1] == '.') {
124 ino = msdos_parent_ino(dir,0);
125 iput(dir);
126 if (ino < 0) return ino;
127 if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
128 return 0;
129 }
130 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
131 iput(dir);
132 return res;
133 }
134 if (bh) brelse(bh);
135
136 if (!(*result = iget(dir->i_sb,ino))) {
137 iput(dir);
138 return -EACCES;
139 }
140 if (MSDOS_I(*result)->i_busy) {
141 iput(*result);
142 iput(dir);
143 return -ENOENT;
144 }
145 while (MSDOS_I(*result)->i_old) {
146 next = MSDOS_I(*result)->i_old;
147 iput(*result);
148 if (!(*result = iget(next->i_sb,next->i_ino))) {
149 fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
150 iput(dir);
151 return -ENOENT;
152 }
153 }
154 iput(dir);
155 return 0;
156 }
157
158
159
160
161 static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
162 struct inode **result)
163 {
164 struct buffer_head *bh;
165 struct msdos_dir_entry *de;
166 int res,ino;
167
168 if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) {
169 if (res != -ENOENT) return res;
170 if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
171 if ((res = msdos_add_cluster(dir)) < 0) return res;
172 if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res;
173 }
174 memcpy(de->name,name,MSDOS_NAME);
175 de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
176 de->start = 0;
177 date_unix2dos(CURRENT_TIME,&de->time,&de->date);
178 de->size = 0;
179 bh->b_dirt = 1;
180 if ((*result = iget(dir->i_sb,ino)) != NULL)
181 msdos_read_inode(*result);
182 brelse(bh);
183 if (!*result) return -EIO;
184 (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
185 CURRENT_TIME;
186 (*result)->i_dirt = 1;
187 return 0;
188 }
189
190
191 int msdos_create(struct inode *dir,const char *name,int len,int mode,
192 struct inode **result)
193 {
194 struct buffer_head *bh;
195 struct msdos_dir_entry *de;
196 char msdos_name[MSDOS_NAME];
197 int ino,res;
198
199 if (!dir) return -ENOENT;
200 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
201 msdos_name,0)) < 0) {
202 iput(dir);
203 return res;
204 }
205 lock_creation();
206 if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
207 unlock_creation();
208 brelse(bh);
209 iput(dir);
210 return -EEXIST;
211 }
212 res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result);
213 unlock_creation();
214 iput(dir);
215 return res;
216 }
217
218
219 #ifdef DEBUG
220
221 static void dump_fat(struct super_block *sb,int start)
222 {
223 printk("[");
224 while (start) {
225 printk("%d ",start);
226 start = fat_access(sb,start,-1);
227 if (!start) {
228 printk("ERROR");
229 break;
230 }
231 if (start == -1) break;
232 }
233 printk("]\n");
234 }
235
236 #endif
237
238
239 int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
240 {
241 struct buffer_head *bh;
242 struct msdos_dir_entry *de;
243 struct inode *inode,*dot;
244 char msdos_name[MSDOS_NAME];
245 int ino,res;
246
247 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
248 msdos_name,0)) < 0) {
249 iput(dir);
250 return res;
251 }
252 lock_creation();
253 if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
254 unlock_creation();
255 brelse(bh);
256 iput(dir);
257 return -EEXIST;
258 }
259 if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
260 unlock_creation();
261 iput(dir);
262 return res;
263 }
264 dir->i_nlink++;
265 inode->i_nlink = 2;
266 MSDOS_I(inode)->i_busy = 1;
267 if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
268 if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
269 goto mkdir_error;
270 dot->i_size = inode->i_size;
271 MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
272 dot->i_nlink = inode->i_nlink;
273 dot->i_dirt = 1;
274 iput(dot);
275 if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
276 goto mkdir_error;
277 unlock_creation();
278 dot->i_size = dir->i_size;
279 MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
280 dot->i_nlink = dir->i_nlink;
281 dot->i_dirt = 1;
282 MSDOS_I(inode)->i_busy = 0;
283 iput(dot);
284 iput(inode);
285 iput(dir);
286 return 0;
287 mkdir_error:
288 iput(inode);
289 if (msdos_rmdir(dir,name,len) < 0)
290 fs_panic(dir->i_sb,"rmdir in mkdir failed");
291 unlock_creation();
292 return res;
293 }
294
295
296 int msdos_rmdir(struct inode *dir,const char *name,int len)
297 {
298 int res,ino,pos;
299 struct buffer_head *bh,*dbh;
300 struct msdos_dir_entry *de,*dde;
301 struct inode *inode;
302
303 bh = NULL;
304 inode = NULL;
305 res = -EPERM;
306 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
307 goto rmdir_done;
308 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
309 res = -ENOENT;
310 if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
311 res = -ENOTDIR;
312 if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
313 res = -EBUSY;
314 if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
315 if (inode->i_count > 1) goto rmdir_done;
316 if (MSDOS_I(inode)->i_start) {
317 res = -ENOTEMPTY;
318 pos = 0;
319 dbh = NULL;
320 while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1)
321 if (!IS_FREE(dde->name) && strncmp(dde->name,MSDOS_DOT,
322 MSDOS_NAME) && strncmp(dde->name,MSDOS_DOTDOT,
323 MSDOS_NAME)) goto rmdir_done;
324 if (dbh) brelse(dbh);
325 }
326 inode->i_nlink = 0;
327 dir->i_mtime = CURRENT_TIME;
328 dir->i_nlink--;
329 inode->i_dirt = dir->i_dirt = 1;
330 de->name[0] = DELETED_FLAG;
331 bh->b_dirt = 1;
332 res = 0;
333 rmdir_done:
334 brelse(bh);
335 iput(dir);
336 iput(inode);
337 return res;
338 }
339
340
341 int msdos_unlink(struct inode *dir,const char *name,int len)
342 {
343 int res,ino;
344 struct buffer_head *bh;
345 struct msdos_dir_entry *de;
346 struct inode *inode;
347
348 bh = NULL;
349 inode = NULL;
350 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
351 goto unlink_done;
352 if (!(inode = iget(dir->i_sb,ino))) {
353 res = -ENOENT;
354 goto unlink_done;
355 }
356 if (!S_ISREG(inode->i_mode)) {
357 res = -EPERM;
358 goto unlink_done;
359 }
360 inode->i_nlink = 0;
361 MSDOS_I(inode)->i_busy = 1;
362 inode->i_dirt = 1;
363 de->name[0] = DELETED_FLAG;
364 bh->b_dirt = 1;
365 unlink_done:
366 brelse(bh);
367 iput(inode);
368 iput(dir);
369 return res;
370 }
371
372
373 static int rename_same_dir(struct inode *old_dir,char *old_name,
374 struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
375 struct msdos_dir_entry *old_de,int old_ino)
376 {
377 struct buffer_head *new_bh;
378 struct msdos_dir_entry *new_de;
379 struct inode *new_inode,*old_inode;
380 int new_ino;
381 int exists;
382
383 if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
384 exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
385 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
386 if (exists) brelse(new_bh);
387 return -ENOENT;
388 }
389 if (exists) {
390 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
391 brelse(new_bh);
392 return -EIO;
393 }
394 if (S_ISDIR(new_inode->i_mode)) {
395 iput(new_inode);
396 brelse(new_bh);
397 return -EPERM;
398 }
399 new_inode->i_nlink = 0;
400 MSDOS_I(new_inode)->i_busy = 1;
401 new_inode->i_dirt = 1;
402 new_de->name[0] = DELETED_FLAG;
403 new_bh->b_dirt = 1;
404 iput(new_inode);
405 brelse(new_bh);
406 }
407 memcpy(old_de->name,new_name,MSDOS_NAME);
408 old_bh->b_dirt = 1;
409 if (MSDOS_SB(old_dir->i_sb)->conversion == 'a')
410 if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
411 msdos_read_inode(old_inode);
412 iput(old_inode);
413 }
414 return 0;
415 }
416
417
418 static int rename_diff_dir(struct inode *old_dir,char *old_name,
419 struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
420 struct msdos_dir_entry *old_de,int old_ino)
421 {
422 struct buffer_head *new_bh,*free_bh,*dotdot_bh;
423 struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
424 struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
425 int new_ino,free_ino,dotdot_ino;
426 int error,exists,ino;
427
428 if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
429 if (old_ino == new_dir->i_ino) return -EINVAL;
430 if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
431 while (walk->i_ino != MSDOS_ROOT_INO) {
432 ino = msdos_parent_ino(walk,1);
433 iput(walk);
434 if (ino < 0) return ino;
435 if (ino == old_ino) return -EINVAL;
436 if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
437 }
438 iput(walk);
439 while ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) <
440 0) {
441 if (error != -ENOENT) return error;
442 error = msdos_add_cluster(new_dir);
443 if (error) return error;
444 }
445 exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
446 if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
447 brelse(free_bh);
448 if (exists) brelse(new_bh);
449 return -EIO;
450 }
451 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
452 iput(old_inode);
453 brelse(free_bh);
454 if (exists) brelse(new_bh);
455 return -ENOENT;
456 }
457 new_inode = NULL;
458 if (exists) {
459 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
460 iput(old_inode);
461 brelse(new_bh);
462 return -EIO;
463 }
464 if (S_ISDIR(new_inode->i_mode)) {
465 iput(new_inode);
466 iput(old_inode);
467 brelse(new_bh);
468 return -EPERM;
469 }
470 new_inode->i_nlink = 0;
471 MSDOS_I(new_inode)->i_busy = 1;
472 new_inode->i_dirt = 1;
473 new_de->name[0] = DELETED_FLAG;
474 new_bh->b_dirt = 1;
475 }
476 memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
477 memcpy(free_de->name,new_name,MSDOS_NAME);
478 if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
479 free_de->name[0] = DELETED_FLAG;
480
481 brelse(free_bh);
482 if (exists) {
483 iput(new_inode);
484 brelse(new_bh);
485 }
486 return -EIO;
487 }
488 msdos_read_inode(free_inode);
489 MSDOS_I(old_inode)->i_busy = 1;
490 cache_inval_inode(old_inode);
491 old_inode->i_dirt = 1;
492 old_de->name[0] = DELETED_FLAG;
493 old_bh->b_dirt = 1;
494 free_bh->b_dirt = 1;
495 if (!exists) iput(free_inode);
496 else {
497 MSDOS_I(new_inode)->i_depend = free_inode;
498 MSDOS_I(free_inode)->i_old = new_inode;
499
500 iput(new_inode);
501 brelse(new_bh);
502 }
503 if (S_ISDIR(old_inode->i_mode)) {
504 if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
505 &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
506 if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
507 brelse(dotdot_bh);
508 error = -EIO;
509 goto rename_done;
510 }
511 dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
512 MSDOS_I(new_dir)->i_start;
513 dotdot_inode->i_dirt = 1;
514 dotdot_bh->b_dirt = 1;
515 old_dir->i_nlink--;
516 new_dir->i_nlink++;
517
518 dotdot_inode->i_nlink = new_dir->i_nlink;
519 iput(dotdot_inode);
520 brelse(dotdot_bh);
521 }
522 error = 0;
523 rename_done:
524 brelse(free_bh);
525 iput(old_inode);
526 return error;
527 }
528
529
530 int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
531 struct inode *new_dir,const char *new_name,int new_len)
532 {
533 char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
534 struct buffer_head *old_bh;
535 struct msdos_dir_entry *old_de;
536 int old_ino,error;
537
538 if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
539 old_name,old_len,old_msdos_name,1)) < 0) goto rename_done;
540 if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
541 new_name,new_len,new_msdos_name,0)) < 0) goto rename_done;
542 if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
543 &old_ino)) < 0) goto rename_done;
544 lock_creation();
545 if (old_dir == new_dir)
546 error = rename_same_dir(old_dir,old_msdos_name,new_dir,
547 new_msdos_name,old_bh,old_de,old_ino);
548 else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
549 new_msdos_name,old_bh,old_de,old_ino);
550 unlock_creation();
551 brelse(old_bh);
552 rename_done:
553 iput(old_dir);
554 iput(new_dir);
555 return error;
556 }