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