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_dev,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_dev,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_dev,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_dev,ino)) msdos_read_inode(*result);
184 brelse(bh);
185 if (!*result) return -EIO;
186 (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
187 CURRENT_TIME;
188 (*result)->i_dirt = 1;
189 return 0;
190 }
191
192
193 int msdos_create(struct inode *dir,const char *name,int len,int mode,
194 struct inode **result)
195 {
196 struct buffer_head *bh;
197 struct msdos_dir_entry *de;
198 char msdos_name[MSDOS_NAME];
199 int ino,res;
200
201 if (!dir) return -ENOENT;
202 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
203 msdos_name)) < 0) {
204 iput(dir);
205 return res;
206 }
207 lock_creation();
208 if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
209 unlock_creation();
210 brelse(bh);
211 iput(dir);
212 return -EEXIST;
213 }
214 res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result);
215 unlock_creation();
216 iput(dir);
217 return res;
218 }
219
220
221 #ifdef DEBUG
222
223 static void dump_fat(struct super_block *sb,int start)
224 {
225 printk("[");
226 while (start) {
227 printk("%d ",start);
228 start = fat_access(sb,start,-1);
229 if (!start) {
230 printk("ERROR");
231 break;
232 }
233 if (start == -1) break;
234 }
235 printk("]\n");
236 }
237
238 #endif
239
240
241 int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
242 {
243 struct buffer_head *bh;
244 struct msdos_dir_entry *de;
245 struct inode *inode,*dot;
246 char msdos_name[MSDOS_NAME];
247 int ino,res;
248
249 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
250 msdos_name)) < 0) {
251 iput(dir);
252 return res;
253 }
254 lock_creation();
255 if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
256 unlock_creation();
257 brelse(bh);
258 iput(dir);
259 return -EEXIST;
260 }
261 if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
262 unlock_creation();
263 iput(dir);
264 return res;
265 }
266 dir->i_nlink++;
267 inode->i_nlink = 2;
268 MSDOS_I(inode)->i_busy = 1;
269 if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
270 if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
271 goto mkdir_error;
272 dot->i_size = inode->i_size;
273 MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
274 dot->i_nlink = inode->i_nlink;
275 dot->i_dirt = 1;
276 iput(dot);
277 if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
278 goto mkdir_error;
279 unlock_creation();
280 dot->i_size = dir->i_size;
281 MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
282 dot->i_nlink = dir->i_nlink;
283 dot->i_dirt = 1;
284 MSDOS_I(inode)->i_busy = 0;
285 iput(dot);
286 iput(inode);
287 iput(dir);
288 return 0;
289 mkdir_error:
290 iput(inode);
291 if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed");
292 unlock_creation();
293 return res;
294 }
295
296
297 int msdos_rmdir(struct inode *dir,const char *name,int len)
298 {
299 int res,ino,pos;
300 struct buffer_head *bh,*dbh;
301 struct msdos_dir_entry *de,*dde;
302 struct inode *inode;
303
304 bh = NULL;
305 inode = NULL;
306 res = -EINVAL;
307 if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
308 get_fs_byte(name+1) == '.'))) goto rmdir_done;
309 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
310 res = -ENOENT;
311 if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done;
312 res = -ENOTDIR;
313 if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
314 res = -EBUSY;
315 if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
316 if (inode->i_count > 1) goto rmdir_done;
317 if (MSDOS_I(inode)->i_start) {
318 res = -ENOTEMPTY;
319 pos = 0;
320 dbh = NULL;
321 while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1)
322 if (dde->name[0] && ((unsigned char *) dde->name)[0] !=
323 DELETED_FLAG && strncmp(dde->name,MSDOS_DOT,
324 MSDOS_NAME) && strncmp(dde->name,MSDOS_DOTDOT,
325 MSDOS_NAME)) goto rmdir_done;
326 if (dbh) brelse(dbh);
327 }
328 inode->i_nlink = 0;
329 dir->i_mtime = CURRENT_TIME;
330 dir->i_nlink--;
331 inode->i_dirt = dir->i_dirt = 1;
332 de->name[0] = DELETED_FLAG;
333 bh->b_dirt = 1;
334 res = 0;
335 rmdir_done:
336 brelse(bh);
337 iput(dir);
338 iput(inode);
339 return res;
340 }
341
342
343 int msdos_unlink(struct inode *dir,const char *name,int len)
344 {
345 int res,ino;
346 struct buffer_head *bh;
347 struct msdos_dir_entry *de;
348 struct inode *inode;
349
350 bh = NULL;
351 inode = NULL;
352 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
353 goto unlink_done;
354 if (!(inode = iget(dir->i_dev,ino))) {
355 res = -ENOENT;
356 goto unlink_done;
357 }
358 if (!S_ISREG(inode->i_mode)) {
359 res = -EPERM;
360 goto unlink_done;
361 }
362 inode->i_nlink = 0;
363 MSDOS_I(inode)->i_busy = 1;
364 inode->i_dirt = 1;
365 de->name[0] = DELETED_FLAG;
366 bh->b_dirt = 1;
367 unlink_done:
368 brelse(bh);
369 iput(inode);
370 iput(dir);
371 return res;
372 }
373
374
375 static int rename_same_dir(struct inode *old_dir,char *old_name,
376 struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
377 struct msdos_dir_entry *old_de,int old_ino)
378 {
379 struct buffer_head *new_bh;
380 struct msdos_dir_entry *new_de;
381 struct inode *new_inode,*old_inode;
382 int new_ino;
383 int exists;
384
385 if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
386 exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
387 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
388 if (exists) brelse(new_bh);
389 return -ENOENT;
390 }
391 if (exists) {
392 if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
393 brelse(new_bh);
394 return -EIO;
395 }
396 if (S_ISDIR(new_inode->i_mode)) {
397 iput(new_inode);
398 brelse(new_bh);
399 return -EPERM;
400 }
401 new_inode->i_nlink = 0;
402 MSDOS_I(new_inode)->i_busy = 1;
403 new_inode->i_dirt = 1;
404 new_de->name[0] = DELETED_FLAG;
405 new_bh->b_dirt = 1;
406 iput(new_inode);
407 brelse(new_bh);
408 }
409 memcpy(old_de->name,new_name,MSDOS_NAME);
410 old_bh->b_dirt = 1;
411 if (MSDOS_SB(old_dir->i_sb)->conversion == 'a')
412 if (old_inode = iget(old_dir->i_dev,old_ino)) {
413 msdos_read_inode(old_inode);
414 iput(old_inode);
415 }
416 return 0;
417 }
418
419
420 static int rename_diff_dir(struct inode *old_dir,char *old_name,
421 struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
422 struct msdos_dir_entry *old_de,int old_ino)
423 {
424 struct buffer_head *new_bh,*free_bh,*dotdot_bh;
425 struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
426 struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
427 int new_ino,free_ino,dotdot_ino;
428 int error,exists,ino;
429
430 if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
431 if (old_ino == new_dir->i_ino) return -EINVAL;
432 if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO;
433 while (walk->i_ino != MSDOS_ROOT_INO) {
434 ino = msdos_parent_ino(walk,1);
435 iput(walk);
436 if (ino < 0) return ino;
437 if (ino == old_ino) return -EINVAL;
438 if (!(walk = iget(new_dir->i_dev,ino))) return -EIO;
439 }
440 iput(walk);
441 if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0)
442 return error;
443 exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)
444 >= 0;
445 if (!(old_inode = iget(old_dir->i_dev,old_ino))) {
446 brelse(free_bh);
447 if (exists) brelse(new_bh);
448 return -EIO;
449 }
450 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
451 iput(old_inode);
452 brelse(free_bh);
453 if (exists) brelse(new_bh);
454 return -ENOENT;
455 }
456 new_inode = NULL;
457 if (exists) {
458 if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
459 iput(old_inode);
460 brelse(new_bh);
461 return -EIO;
462 }
463 if (S_ISDIR(new_inode->i_mode)) {
464 iput(new_inode);
465 iput(old_inode);
466 brelse(new_bh);
467 return -EPERM;
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 new_bh->b_dirt = 1;
474 }
475 memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
476 memcpy(free_de->name,new_name,MSDOS_NAME);
477 if (!(free_inode = iget(new_dir->i_dev,free_ino))) {
478 free_de->name[0] = DELETED_FLAG;
479
480 brelse(free_bh);
481 if (exists) {
482 iput(new_inode);
483 brelse(new_bh);
484 }
485 return -EIO;
486 }
487 msdos_read_inode(free_inode);
488 MSDOS_I(old_inode)->i_busy = 1;
489 cache_inval_inode(old_inode);
490 old_inode->i_dirt = 1;
491 old_de->name[0] = DELETED_FLAG;
492 old_bh->b_dirt = 1;
493 free_bh->b_dirt = 1;
494 if (!exists) iput(free_inode);
495 else {
496 MSDOS_I(new_inode)->i_depend = free_inode;
497 MSDOS_I(free_inode)->i_old = new_inode;
498
499 iput(new_inode);
500 brelse(new_bh);
501 }
502 if (S_ISDIR(old_inode->i_mode)) {
503 if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
504 &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
505 if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) {
506 brelse(dotdot_bh);
507 error = -EIO;
508 goto rename_done;
509 }
510 dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
511 MSDOS_I(new_dir)->i_start;
512 dotdot_inode->i_dirt = 1;
513 dotdot_bh->b_dirt = 1;
514 iput(dotdot_inode);
515 brelse(dotdot_bh);
516 old_dir->i_nlink--;
517 new_dir->i_nlink++;
518
519 }
520 error = 0;
521 rename_done:
522 brelse(free_bh);
523 iput(old_inode);
524 return error;
525 }
526
527
528 int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
529 struct inode *new_dir,const char *new_name,int new_len)
530 {
531 char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
532 struct buffer_head *old_bh;
533 struct msdos_dir_entry *old_de;
534 int old_ino,error;
535
536 if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
537 old_name,old_len,old_msdos_name)) < 0) goto rename_done;
538 if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
539 new_name,new_len,new_msdos_name)) < 0) goto rename_done;
540 if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
541 &old_ino)) < 0) goto rename_done;
542 lock_creation();
543 if (old_dir == new_dir)
544 error = rename_same_dir(old_dir,old_msdos_name,new_dir,
545 new_msdos_name,old_bh,old_de,old_ino);
546 else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
547 new_msdos_name,old_bh,old_de,old_ino);
548 unlock_creation();
549 brelse(old_bh);
550 rename_done:
551 iput(old_dir);
552 iput(new_dir);
553 return error;
554 }