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