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 {
35 char *walk,**reserved;
36 char c;
37 int space;
38
39 if (get_fs_byte(name) == DELETED_FLAG) return -EINVAL;
40 if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
41 get_fs_byte(name+1) == '.'))) {
42 memset(res+1,' ',10);
43 while (len--) *res++ = '.';
44 return 0;
45 }
46 space = 0;
47 c = 0;
48 for (walk = res; len && walk-res < 8; walk++) {
49 c = get_fs_byte(name++);
50 len--;
51 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
52 if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
53 if (c >= 'A' && c <= 'Z') {
54 if (conv == 's') return -EINVAL;
55 c += 32;
56 }
57 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
58 if (c == '.') break;
59 space = c == ' ';
60 *walk = c >= 'a' && c <= 'z' ? c-32 : c;
61 }
62 if (space) return -EINVAL;
63 if (conv == 's' && len && c != '.') {
64 c = get_fs_byte(name++);
65 len--;
66 if (c != '.') return -EINVAL;
67 }
68 while (c != '.' && len--) c = get_fs_byte(name++);
69 if (walk == res) return -EINVAL;
70 if (c == '.') {
71 while (walk-res < 8) *walk++ = ' ';
72 while (len > 0 && walk-res < MSDOS_NAME) {
73 c = get_fs_byte(name++);
74 len--;
75 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
76 if (conv == 's' && strchr(bad_if_strict,c))
77 return -EINVAL;
78 if (c < ' ' || c == ':' || c == '\\' || c == '.')
79 return -EINVAL;
80 if (c >= 'A' && c <= 'Z') {
81 if (conv == 's') return -EINVAL;
82 c += 32;
83 }
84 space = c == ' ';
85 *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
86 }
87 if (space) return -EINVAL;
88 if (conv == 's' && len) return -EINVAL;
89 }
90 while (walk-res < MSDOS_NAME) *walk++ = ' ';
91 for (reserved = reserved_names; *reserved; reserved++)
92 if (!strncmp(res,*reserved,8)) return -EINVAL;
93 return 0;
94 }
95
96
97
98
99 static int msdos_find(struct inode *dir,const char *name,int len,
100 struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
101 {
102 char msdos_name[MSDOS_NAME];
103 int res;
104
105 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
106 msdos_name)) < 0) return res;
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 int ino,res;
115 struct msdos_dir_entry *de;
116 struct buffer_head *bh;
117 struct inode *next;
118
119 *result = NULL;
120 if (!dir) return -ENOENT;
121 if (!S_ISDIR(dir->i_mode)) {
122 iput(dir);
123 return -ENOENT;
124 }
125 if (len == 1 && get_fs_byte(name) == '.') {
126 *result = dir;
127 return 0;
128 }
129 if (len == 2 && get_fs_byte(name) == '.' && get_fs_byte(name+1) == '.')
130 {
131 ino = msdos_parent_ino(dir,0);
132 iput(dir);
133 if (ino < 0) return ino;
134 if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
135 return 0;
136 }
137 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
138 iput(dir);
139 return res;
140 }
141 if (bh) brelse(bh);
142
143 if (!(*result = iget(dir->i_sb,ino))) {
144 iput(dir);
145 return -EACCES;
146 }
147 if (MSDOS_I(*result)->i_busy) {
148 iput(*result);
149 iput(dir);
150 return -ENOENT;
151 }
152 while (MSDOS_I(*result)->i_old) {
153 next = MSDOS_I(*result)->i_old;
154 iput(*result);
155 if (!(*result = iget(next->i_sb,next->i_ino)))
156 panic("msdos_lookup: Can't happen");
157 }
158 iput(dir);
159 return 0;
160 }
161
162
163
164
165 static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
166 struct inode **result)
167 {
168 struct buffer_head *bh;
169 struct msdos_dir_entry *de;
170 int res,ino;
171
172 if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) {
173 if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
174 if ((res = msdos_add_cluster(dir)) < 0) return res;
175 if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res;
176 }
177 memcpy(de->name,name,MSDOS_NAME);
178 de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
179 de->start = 0;
180 date_unix2dos(CURRENT_TIME,&de->time,&de->date);
181 de->size = 0;
182 bh->b_dirt = 1;
183 if ((*result = iget(dir->i_sb,ino)) != NULL)
184 msdos_read_inode(*result);
185 brelse(bh);
186 if (!*result) return -EIO;
187 (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
188 CURRENT_TIME;
189 (*result)->i_dirt = 1;
190 return 0;
191 }
192
193
194 int msdos_create(struct inode *dir,const char *name,int len,int mode,
195 struct inode **result)
196 {
197 struct buffer_head *bh;
198 struct msdos_dir_entry *de;
199 char msdos_name[MSDOS_NAME];
200 int ino,res;
201
202 if (!dir) return -ENOENT;
203 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
204 msdos_name)) < 0) {
205 iput(dir);
206 return res;
207 }
208 lock_creation();
209 if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
210 unlock_creation();
211 brelse(bh);
212 iput(dir);
213 return -EEXIST;
214 }
215 res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result);
216 unlock_creation();
217 iput(dir);
218 return res;
219 }
220
221
222 #ifdef DEBUG
223
224 static void dump_fat(struct super_block *sb,int start)
225 {
226 printk("[");
227 while (start) {
228 printk("%d ",start);
229 start = fat_access(sb,start,-1);
230 if (!start) {
231 printk("ERROR");
232 break;
233 }
234 if (start == -1) break;
235 }
236 printk("]\n");
237 }
238
239 #endif
240
241
242 int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
243 {
244 struct buffer_head *bh;
245 struct msdos_dir_entry *de;
246 struct inode *inode,*dot;
247 char msdos_name[MSDOS_NAME];
248 int ino,res;
249
250 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
251 msdos_name)) < 0) {
252 iput(dir);
253 return res;
254 }
255 lock_creation();
256 if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
257 unlock_creation();
258 brelse(bh);
259 iput(dir);
260 return -EEXIST;
261 }
262 if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
263 unlock_creation();
264 iput(dir);
265 return res;
266 }
267 dir->i_nlink++;
268 inode->i_nlink = 2;
269 MSDOS_I(inode)->i_busy = 1;
270 if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
271 if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
272 goto mkdir_error;
273 dot->i_size = inode->i_size;
274 MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
275 dot->i_nlink = inode->i_nlink;
276 dot->i_dirt = 1;
277 iput(dot);
278 if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
279 goto mkdir_error;
280 unlock_creation();
281 dot->i_size = dir->i_size;
282 MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
283 dot->i_nlink = dir->i_nlink;
284 dot->i_dirt = 1;
285 MSDOS_I(inode)->i_busy = 0;
286 iput(dot);
287 iput(inode);
288 iput(dir);
289 return 0;
290 mkdir_error:
291 iput(inode);
292 if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed");
293 unlock_creation();
294 return res;
295 }
296
297
298 int msdos_rmdir(struct inode *dir,const char *name,int len)
299 {
300 int res,ino,pos;
301 struct buffer_head *bh,*dbh;
302 struct msdos_dir_entry *de,*dde;
303 struct inode *inode;
304
305 bh = NULL;
306 inode = NULL;
307 res = -EINVAL;
308 if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
309 get_fs_byte(name+1) == '.'))) goto rmdir_done;
310 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
311 res = -ENOENT;
312 if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
313 res = -ENOTDIR;
314 if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
315 res = -EBUSY;
316 if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
317 if (inode->i_count > 1) goto rmdir_done;
318 if (MSDOS_I(inode)->i_start) {
319 res = -ENOTEMPTY;
320 pos = 0;
321 dbh = NULL;
322 while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1)
323 if (dde->name[0] && ((unsigned char *) dde->name)[0] !=
324 DELETED_FLAG && strncmp(dde->name,MSDOS_DOT,
325 MSDOS_NAME) && strncmp(dde->name,MSDOS_DOTDOT,
326 MSDOS_NAME)) goto rmdir_done;
327 if (dbh) brelse(dbh);
328 }
329 inode->i_nlink = 0;
330 dir->i_mtime = CURRENT_TIME;
331 dir->i_nlink--;
332 inode->i_dirt = dir->i_dirt = 1;
333 de->name[0] = DELETED_FLAG;
334 bh->b_dirt = 1;
335 res = 0;
336 rmdir_done:
337 brelse(bh);
338 iput(dir);
339 iput(inode);
340 return res;
341 }
342
343
344 int msdos_unlink(struct inode *dir,const char *name,int len)
345 {
346 int res,ino;
347 struct buffer_head *bh;
348 struct msdos_dir_entry *de;
349 struct inode *inode;
350
351 bh = NULL;
352 inode = NULL;
353 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
354 goto unlink_done;
355 if (!(inode = iget(dir->i_sb,ino))) {
356 res = -ENOENT;
357 goto unlink_done;
358 }
359 if (!S_ISREG(inode->i_mode)) {
360 res = -EPERM;
361 goto unlink_done;
362 }
363 inode->i_nlink = 0;
364 MSDOS_I(inode)->i_busy = 1;
365 inode->i_dirt = 1;
366 de->name[0] = DELETED_FLAG;
367 bh->b_dirt = 1;
368 unlink_done:
369 brelse(bh);
370 iput(inode);
371 iput(dir);
372 return res;
373 }
374
375
376 static int rename_same_dir(struct inode *old_dir,char *old_name,
377 struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
378 struct msdos_dir_entry *old_de,int old_ino)
379 {
380 struct buffer_head *new_bh;
381 struct msdos_dir_entry *new_de;
382 struct inode *new_inode,*old_inode;
383 int new_ino;
384 int exists;
385
386 if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
387 exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
388 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
389 if (exists) brelse(new_bh);
390 return -ENOENT;
391 }
392 if (exists) {
393 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
394 brelse(new_bh);
395 return -EIO;
396 }
397 if (S_ISDIR(new_inode->i_mode)) {
398 iput(new_inode);
399 brelse(new_bh);
400 return -EPERM;
401 }
402 new_inode->i_nlink = 0;
403 MSDOS_I(new_inode)->i_busy = 1;
404 new_inode->i_dirt = 1;
405 new_de->name[0] = DELETED_FLAG;
406 new_bh->b_dirt = 1;
407 iput(new_inode);
408 brelse(new_bh);
409 }
410 memcpy(old_de->name,new_name,MSDOS_NAME);
411 old_bh->b_dirt = 1;
412 if (MSDOS_SB(old_dir->i_sb)->conversion == 'a')
413 if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
414 msdos_read_inode(old_inode);
415 iput(old_inode);
416 }
417 return 0;
418 }
419
420
421 static int rename_diff_dir(struct inode *old_dir,char *old_name,
422 struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
423 struct msdos_dir_entry *old_de,int old_ino)
424 {
425 struct buffer_head *new_bh,*free_bh,*dotdot_bh;
426 struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
427 struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
428 int new_ino,free_ino,dotdot_ino;
429 int error,exists,ino;
430
431 if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
432 if (old_ino == new_dir->i_ino) return -EINVAL;
433 if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
434 while (walk->i_ino != MSDOS_ROOT_INO) {
435 ino = msdos_parent_ino(walk,1);
436 iput(walk);
437 if (ino < 0) return ino;
438 if (ino == old_ino) return -EINVAL;
439 if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
440 }
441 iput(walk);
442 if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0)
443 return error;
444 exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)
445 >= 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)) < 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) 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 }