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