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