OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [udf/] [namei.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * namei.c
3
 *
4
 * PURPOSE
5
 *      Inode name handling routines for the OSTA-UDF(tm) filesystem.
6
 *
7
 * CONTACTS
8
 *      E-mail regarding any portion of the Linux UDF file system should be
9
 *      directed to the development team mailing list (run by majordomo):
10
 *              linux_udf@hpesjro.fc.hp.com
11
 *
12
 * COPYRIGHT
13
 *      This file is distributed under the terms of the GNU General Public
14
 *      License (GPL). Copies of the GPL can be obtained from:
15
 *              ftp://prep.ai.mit.edu/pub/gnu/GPL
16
 *      Each contributing author retains all rights to their own work.
17
 *
18
 *  (C) 1998-2001 Ben Fennema
19
 *  (C) 1999-2000 Stelias Computing Inc
20
 *
21
 * HISTORY
22
 *
23
 *  12/12/98 blf  Created. Split out the lookup code from dir.c
24
 *  04/19/99 blf  link, mknod, symlink support
25
 */
26
 
27
#include "udfdecl.h"
28
 
29
#include "udf_i.h"
30
#include "udf_sb.h"
31
#include <linux/string.h>
32
#include <linux/errno.h>
33
#include <linux/mm.h>
34
#include <linux/slab.h>
35
#include <linux/quotaops.h>
36
#include <linux/locks.h>
37
#include <linux/smp_lock.h>
38
 
39
static inline int udf_match(int len, const char * const name, struct qstr *qs)
40
{
41
        if (len != qs->len)
42
                return 0;
43
        return !memcmp(name, qs->name, len);
44
}
45
 
46
int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
47
        struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
48
        uint8_t *impuse, uint8_t *fileident)
49
{
50
        uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
51
        uint16_t crc;
52
        uint8_t checksum = 0;
53
        int i;
54
        int offset;
55
        uint16_t liu = le16_to_cpu(cfi->lengthOfImpUse);
56
        uint8_t lfi = cfi->lengthFileIdent;
57
        int padlen = fibh->eoffset - fibh->soffset - liu - lfi -
58
                sizeof(struct fileIdentDesc);
59
 
60
        offset = fibh->soffset + sizeof(struct fileIdentDesc);
61
 
62
        if (impuse)
63
        {
64
                if (offset + liu < 0)
65
                        memcpy((uint8_t *)sfi->impUse, impuse, liu);
66
                else if (offset >= 0)
67
                        memcpy(fibh->ebh->b_data + offset, impuse, liu);
68
                else
69
                {
70
                        memcpy((uint8_t *)sfi->impUse, impuse, -offset);
71
                        memcpy(fibh->ebh->b_data, impuse - offset, liu + offset);
72
                }
73
        }
74
 
75
        offset += liu;
76
 
77
        if (fileident)
78
        {
79
                if (offset + lfi < 0)
80
                        memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi);
81
                else if (offset >= 0)
82
                        memcpy(fibh->ebh->b_data + offset, fileident, lfi);
83
                else
84
                {
85
                        memcpy((uint8_t *)sfi->fileIdent + liu, fileident, -offset);
86
                        memcpy(fibh->ebh->b_data, fileident - offset, lfi + offset);
87
                }
88
        }
89
 
90
        offset += lfi;
91
 
92
        if (offset + padlen < 0)
93
                memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen);
94
        else if (offset >= 0)
95
                memset(fibh->ebh->b_data + offset, 0x00, padlen);
96
        else
97
        {
98
                memset((uint8_t *)sfi->padding + liu + lfi, 0x00, -offset);
99
                memset(fibh->ebh->b_data, 0x00, padlen + offset);
100
        }
101
 
102
        crc = udf_crc((uint8_t *)cfi + sizeof(tag), sizeof(struct fileIdentDesc) -
103
                sizeof(tag), 0);
104
 
105
        if (fibh->sbh == fibh->ebh)
106
                crc = udf_crc((uint8_t *)sfi->impUse,
107
                        crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
108
        else if (sizeof(struct fileIdentDesc) >= -fibh->soffset)
109
                crc = udf_crc(fibh->ebh->b_data + sizeof(struct fileIdentDesc) + fibh->soffset,
110
                        crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
111
        else
112
        {
113
                crc = udf_crc((uint8_t *)sfi->impUse,
114
                        -fibh->soffset - sizeof(struct fileIdentDesc), crc);
115
                crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
116
        }
117
 
118
        cfi->descTag.descCRC = cpu_to_le32(crc);
119
        cfi->descTag.descCRCLength = cpu_to_le16(crclen);
120
 
121
        for (i=0; i<16; i++)
122
                if (i != 4)
123
                        checksum += ((uint8_t *)&cfi->descTag)[i];
124
 
125
        cfi->descTag.tagChecksum = checksum;
126
        if (sizeof(struct fileIdentDesc) <= -fibh->soffset)
127
                memcpy((uint8_t *)sfi, (uint8_t *)cfi, sizeof(struct fileIdentDesc));
128
        else
129
        {
130
                memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset);
131
                memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset,
132
                        sizeof(struct fileIdentDesc) + fibh->soffset);
133
        }
134
 
135
        if (fibh->sbh != fibh->ebh)
136
                mark_buffer_dirty_inode(fibh->ebh, inode);
137
        mark_buffer_dirty_inode(fibh->sbh, inode);
138
        return 0;
139
}
140
 
141
static struct fileIdentDesc *
142
udf_find_entry(struct inode *dir, struct dentry *dentry,
143
        struct udf_fileident_bh *fibh,
144
        struct fileIdentDesc *cfi)
145
{
146
        struct fileIdentDesc *fi=NULL;
147
        loff_t f_pos;
148
        int block, flen;
149
        char fname[255];
150
        char *nameptr;
151
        uint8_t lfi;
152
        uint16_t liu;
153
        loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
154
        lb_addr bloc, eloc;
155
        uint32_t extoffset, elen, offset;
156
        struct buffer_head *bh = NULL;
157
 
158
        if (!dir)
159
                return NULL;
160
 
161
        f_pos = (udf_ext0_offset(dir) >> 2);
162
 
163
        fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
164
        if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
165
                &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
166
        {
167
                offset >>= dir->i_sb->s_blocksize_bits;
168
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
169
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
170
                {
171
                        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
172
                                extoffset -= sizeof(short_ad);
173
                        else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
174
                                extoffset -= sizeof(long_ad);
175
                }
176
                else
177
                        offset = 0;
178
        }
179
        else
180
        {
181
                udf_release_data(bh);
182
                return NULL;
183
        }
184
 
185
        if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
186
        {
187
                udf_release_data(bh);
188
                return NULL;
189
        }
190
 
191
        while ( (f_pos < size) )
192
        {
193
                fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
194
 
195
                if (!fi)
196
                {
197
                        if (fibh->sbh != fibh->ebh)
198
                                udf_release_data(fibh->ebh);
199
                        udf_release_data(fibh->sbh);
200
                        udf_release_data(bh);
201
                        return NULL;
202
                }
203
 
204
                liu = le16_to_cpu(cfi->lengthOfImpUse);
205
                lfi = cfi->lengthFileIdent;
206
 
207
                if (fibh->sbh == fibh->ebh)
208
                {
209
                        nameptr = fi->fileIdent + liu;
210
                }
211
                else
212
                {
213
                        int poffset;    /* Unpaded ending offset */
214
 
215
                        poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;
216
 
217
                        if (poffset >= lfi)
218
                                nameptr = (uint8_t *)(fibh->ebh->b_data + poffset - lfi);
219
                        else
220
                        {
221
                                nameptr = fname;
222
                                memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
223
                                memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
224
                        }
225
                }
226
 
227
                if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
228
                {
229
                        if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )
230
                                continue;
231
                }
232
 
233
                if ( (cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 )
234
                {
235
                        if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )
236
                                continue;
237
                }
238
 
239
                if (!lfi)
240
                        continue;
241
 
242
                if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)))
243
                {
244
                        if (udf_match(flen, fname, &(dentry->d_name)))
245
                        {
246
                                udf_release_data(bh);
247
                                return fi;
248
                        }
249
                }
250
        }
251
        if (fibh->sbh != fibh->ebh)
252
                udf_release_data(fibh->ebh);
253
        udf_release_data(fibh->sbh);
254
        udf_release_data(bh);
255
        return NULL;
256
}
257
 
258
/*
259
 * udf_lookup
260
 *
261
 * PURPOSE
262
 *      Look-up the inode for a given name.
263
 *
264
 * DESCRIPTION
265
 *      Required - lookup_dentry() will return -ENOTDIR if this routine is not
266
 *      available for a directory. The filesystem is useless if this routine is
267
 *      not available for at least the filesystem's root directory.
268
 *
269
 *      This routine is passed an incomplete dentry - it must be completed by
270
 *      calling d_add(dentry, inode). If the name does not exist, then the
271
 *      specified inode must be set to null. An error should only be returned
272
 *      when the lookup fails for a reason other than the name not existing.
273
 *      Note that the directory inode semaphore is held during the call.
274
 *
275
 *      Refer to lookup_dentry() in fs/namei.c
276
 *      lookup_dentry() -> lookup() -> real_lookup() -> .
277
 *
278
 * PRE-CONDITIONS
279
 *      dir                     Pointer to inode of parent directory.
280
 *      dentry                  Pointer to dentry to complete.
281
 *
282
 * POST-CONDITIONS
283
 *      <return>                Zero on success.
284
 *
285
 * HISTORY
286
 *      July 1, 1997 - Andrew E. Mileski
287
 *      Written, tested, and released.
288
 */
289
 
290
static struct dentry *
291
udf_lookup(struct inode *dir, struct dentry *dentry)
292
{
293
        struct inode *inode = NULL;
294
        struct fileIdentDesc cfi, *fi;
295
        struct udf_fileident_bh fibh;
296
 
297
        if (dentry->d_name.len > UDF_NAME_LEN)
298
                return ERR_PTR(-ENAMETOOLONG);
299
 
300
#ifdef UDF_RECOVERY
301
        /* temporary shorthand for specifying files by inode number */
302
        if (!strncmp(dentry->d_name.name, ".B=", 3) )
303
        {
304
                lb_addr lb = { 0, simple_strtoul(dentry->d_name.name+3, NULL, 0) };
305
                inode = udf_iget(dir->i_sb, lb);
306
                if (!inode)
307
                        return ERR_PTR(-EACCES);
308
        }
309
        else
310
#endif /* UDF_RECOVERY */
311
 
312
        if ((fi = udf_find_entry(dir, dentry, &fibh, &cfi)))
313
        {
314
                if (fibh.sbh != fibh.ebh)
315
                        udf_release_data(fibh.ebh);
316
                udf_release_data(fibh.sbh);
317
 
318
                inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
319
                if ( !inode )
320
                        return ERR_PTR(-EACCES);
321
        }
322
        d_add(dentry, inode);
323
        return NULL;
324
}
325
 
326
static struct fileIdentDesc *
327
udf_add_entry(struct inode *dir, struct dentry *dentry,
328
        struct udf_fileident_bh *fibh,
329
        struct fileIdentDesc *cfi, int *err)
330
{
331
        struct super_block *sb;
332
        struct fileIdentDesc *fi=NULL;
333
        struct ustr unifilename;
334
        char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
335
        int namelen;
336
        loff_t f_pos;
337
        int flen;
338
        char *nameptr;
339
        loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
340
        int nfidlen;
341
        uint8_t lfi;
342
        uint16_t liu;
343
        int block;
344
        lb_addr bloc, eloc;
345
        uint32_t extoffset, elen, offset;
346
        struct buffer_head *bh = NULL;
347
 
348
        sb = dir->i_sb;
349
 
350
        if (dentry)
351
        {
352
                if (!dentry->d_name.len)
353
                {
354
                        *err = -EINVAL;
355
                        return NULL;
356
                }
357
 
358
                if ( !(udf_char_to_ustr(&unifilename, dentry->d_name.name, dentry->d_name.len)) )
359
                {
360
                        *err = -ENAMETOOLONG;
361
                        return NULL;
362
                }
363
 
364
                if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
365
                {
366
                        if ( !(namelen = udf_UTF8toCS0(name, &unifilename, UDF_NAME_LEN)) )
367
                        {
368
                                *err = -ENAMETOOLONG;
369
                                return NULL;
370
                        }
371
                }
372
                else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
373
                {
374
                        if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, name, &unifilename, UDF_NAME_LEN)) )
375
                        {
376
                                *err = -ENAMETOOLONG;
377
                                return NULL;
378
                        }
379
                }
380
                else
381
                        return NULL;
382
        }
383
        else
384
                namelen = 0;
385
 
386
        nfidlen = (sizeof(struct fileIdentDesc) + namelen + 3) & ~3;
387
 
388
        f_pos = (udf_ext0_offset(dir) >> 2);
389
 
390
        fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
391
        if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
392
                &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
393
        {
394
                offset >>= dir->i_sb->s_blocksize_bits;
395
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
396
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
397
                {
398
                        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
399
                                extoffset -= sizeof(short_ad);
400
                        else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
401
                                extoffset -= sizeof(long_ad);
402
                }
403
                else
404
                        offset = 0;
405
 
406
                if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
407
                {
408
                        udf_release_data(bh);
409
                        *err = -EIO;
410
                        return NULL;
411
                }
412
 
413
                block = UDF_I_LOCATION(dir).logicalBlockNum;
414
 
415
                while ( (f_pos < size) )
416
                {
417
                        fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
418
 
419
                        if (!fi)
420
                        {
421
                                if (fibh->sbh != fibh->ebh)
422
                                        udf_release_data(fibh->ebh);
423
                                udf_release_data(fibh->sbh);
424
                                udf_release_data(bh);
425
                                *err = -EIO;
426
                                return NULL;
427
                        }
428
 
429
                        liu = le16_to_cpu(cfi->lengthOfImpUse);
430
                        lfi = cfi->lengthFileIdent;
431
 
432
                        if (fibh->sbh == fibh->ebh)
433
                                nameptr = fi->fileIdent + liu;
434
                        else
435
                        {
436
                                int poffset;    /* Unpaded ending offset */
437
 
438
                                poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;
439
 
440
                                if (poffset >= lfi)
441
                                        nameptr = (char *)(fibh->ebh->b_data + poffset - lfi);
442
                                else
443
                                {
444
                                        nameptr = fname;
445
                                        memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
446
                                        memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
447
                                }
448
                        }
449
 
450
                        if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
451
                        {
452
                                if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen)
453
                                {
454
                                        udf_release_data(bh);
455
                                        cfi->descTag.tagSerialNum = cpu_to_le16(1);
456
                                        cfi->fileVersionNum = cpu_to_le16(1);
457
                                        cfi->fileCharacteristics = 0;
458
                                        cfi->lengthFileIdent = namelen;
459
                                        cfi->lengthOfImpUse = cpu_to_le16(0);
460
                                        if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
461
                                                return fi;
462
                                        else
463
                                        {
464
                                                *err = -EIO;
465
                                                return NULL;
466
                                        }
467
                                }
468
                        }
469
 
470
                        if (!lfi || !dentry)
471
                                continue;
472
 
473
                        if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) &&
474
                                udf_match(flen, fname, &(dentry->d_name)))
475
                        {
476
                                if (fibh->sbh != fibh->ebh)
477
                                        udf_release_data(fibh->ebh);
478
                                udf_release_data(fibh->sbh);
479
                                udf_release_data(bh);
480
                                *err = -EEXIST;
481
                                return NULL;
482
                        }
483
                }
484
        }
485
        else
486
        {
487
                block = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(dir), 0);
488
                if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
489
                {
490
                        fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
491
                        fibh->soffset = fibh->eoffset = udf_file_entry_alloc_offset(dir);
492
                }
493
                else
494
                {
495
                        fibh->sbh = fibh->ebh = NULL;
496
                        fibh->soffset = fibh->eoffset = sb->s_blocksize;
497
                }
498
        }
499
 
500
        f_pos += nfidlen;
501
 
502
        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB &&
503
                sb->s_blocksize - fibh->eoffset < nfidlen)
504
        {
505
                udf_release_data(bh);
506
                bh = NULL;
507
                fibh->soffset -= udf_ext0_offset(dir);
508
                fibh->eoffset -= udf_ext0_offset(dir);
509
                f_pos -= (udf_ext0_offset(dir) >> 2);
510
                if (fibh->sbh != fibh->ebh)
511
                        udf_release_data(fibh->ebh);
512
                udf_release_data(fibh->sbh);
513
                if (!(fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err)))
514
                        return NULL;
515
                bloc = UDF_I_LOCATION(dir);
516
                eloc.logicalBlockNum = block;
517
                eloc.partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
518
                elen = dir->i_sb->s_blocksize;
519
                extoffset = udf_file_entry_alloc_offset(dir);
520
                if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
521
                        extoffset += sizeof(short_ad);
522
                else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
523
                        extoffset += sizeof(long_ad);
524
        }
525
 
526
        if (sb->s_blocksize - fibh->eoffset >= nfidlen)
527
        {
528
                fibh->soffset = fibh->eoffset;
529
                fibh->eoffset += nfidlen;
530
                if (fibh->sbh != fibh->ebh)
531
                {
532
                        udf_release_data(fibh->sbh);
533
                        fibh->sbh = fibh->ebh;
534
                }
535
 
536
                if (UDF_I_ALLOCTYPE(dir) != ICBTAG_FLAG_AD_IN_ICB)
537
                        block = eloc.logicalBlockNum + ((elen - 1) >>
538
                                dir->i_sb->s_blocksize_bits);
539
                else
540
                        block = UDF_I_LOCATION(dir).logicalBlockNum;
541
 
542
                fi = (struct fileIdentDesc *)(fibh->sbh->b_data + fibh->soffset);
543
        }
544
        else
545
        {
546
                fibh->soffset = fibh->eoffset - sb->s_blocksize;
547
                fibh->eoffset += nfidlen - sb->s_blocksize;
548
                if (fibh->sbh != fibh->ebh)
549
                {
550
                        udf_release_data(fibh->sbh);
551
                        fibh->sbh = fibh->ebh;
552
                }
553
 
554
                block = eloc.logicalBlockNum + ((elen - 1) >>
555
                        dir->i_sb->s_blocksize_bits);
556
 
557
                if (!(fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
558
                {
559
                        udf_release_data(bh);
560
                        udf_release_data(fibh->sbh);
561
                        return NULL;
562
                }
563
 
564
                if (!(fibh->soffset))
565
                {
566
                        if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) ==
567
                                (EXT_RECORDED_ALLOCATED >> 30))
568
                        {
569
                                block = eloc.logicalBlockNum + ((elen - 1) >>
570
                                        dir->i_sb->s_blocksize_bits);
571
                        }
572
                        else
573
                                block ++;
574
 
575
                        udf_release_data(fibh->sbh);
576
                        fibh->sbh = fibh->ebh;
577
                        fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
578
                }
579
                else
580
                {
581
                        fi = (struct fileIdentDesc *)
582
                                (fibh->sbh->b_data + sb->s_blocksize + fibh->soffset);
583
                }
584
        }
585
 
586
        memset(cfi, 0, sizeof(struct fileIdentDesc));
587
        if (UDF_SB_UDFREV(sb) >= 0x0200)
588
                udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block, sizeof(tag));
589
        else
590
                udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block, sizeof(tag));
591
        cfi->fileVersionNum = cpu_to_le16(1);
592
        cfi->lengthFileIdent = namelen;
593
        cfi->lengthOfImpUse = cpu_to_le16(0);
594
        if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
595
        {
596
                udf_release_data(bh);
597
                dir->i_size += nfidlen;
598
                if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
599
                        UDF_I_LENALLOC(dir) += nfidlen;
600
                dir->i_version = ++event;
601
                mark_inode_dirty(dir);
602
                return fi;
603
        }
604
        else
605
        {
606
                udf_release_data(bh);
607
                if (fibh->sbh != fibh->ebh)
608
                        udf_release_data(fibh->ebh);
609
                udf_release_data(fibh->sbh);
610
                *err = -EIO;
611
                return NULL;
612
        }
613
}
614
 
615
static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
616
        struct udf_fileident_bh *fibh, struct fileIdentDesc *cfi)
617
{
618
        cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
619
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
620
                memset(&(cfi->icb), 0x00, sizeof(long_ad));
621
        return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
622
}
623
 
624
static int udf_create(struct inode *dir, struct dentry *dentry, int mode)
625
{
626
        struct udf_fileident_bh fibh;
627
        struct inode *inode;
628
        struct fileIdentDesc cfi, *fi;
629
        int err;
630
 
631
        inode = udf_new_inode(dir, mode, &err);
632
        if (!inode)
633
                return err;
634
 
635
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
636
                inode->i_data.a_ops = &udf_adinicb_aops;
637
        else
638
                inode->i_data.a_ops = &udf_aops;
639
        inode->i_op = &udf_file_inode_operations;
640
        inode->i_fop = &udf_file_operations;
641
        inode->i_mode = mode;
642
        mark_inode_dirty(inode);
643
 
644
        if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
645
        {
646
                inode->i_nlink --;
647
                mark_inode_dirty(inode);
648
                iput(inode);
649
                return err;
650
        }
651
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
652
        cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
653
        *(uint32_t *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
654
                cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
655
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
656
        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
657
        {
658
                mark_inode_dirty(dir);
659
                dir->i_version = ++event;
660
        }
661
        if (fibh.sbh != fibh.ebh)
662
                udf_release_data(fibh.ebh);
663
        udf_release_data(fibh.sbh);
664
        d_instantiate(dentry, inode);
665
        return 0;
666
}
667
 
668
static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
669
{
670
        struct inode * inode;
671
        struct udf_fileident_bh fibh;
672
        int err;
673
        struct fileIdentDesc cfi, *fi;
674
 
675
        err = -EIO;
676
        inode = udf_new_inode(dir, mode, &err);
677
        if (!inode)
678
                goto out;
679
 
680
        inode->i_uid = current->fsuid;
681
        init_special_inode(inode, mode, rdev);
682
        if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
683
        {
684
                inode->i_nlink --;
685
                mark_inode_dirty(inode);
686
                iput(inode);
687
                return err;
688
        }
689
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
690
        cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
691
        *(uint32_t *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
692
                cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
693
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
694
        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
695
        {
696
                mark_inode_dirty(dir);
697
                dir->i_version = ++event;
698
        }
699
        mark_inode_dirty(inode);
700
 
701
        if (fibh.sbh != fibh.ebh)
702
                udf_release_data(fibh.ebh);
703
        udf_release_data(fibh.sbh);
704
        d_instantiate(dentry, inode);
705
        err = 0;
706
out:
707
        return err;
708
}
709
 
710
static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
711
{
712
        struct inode * inode;
713
        struct udf_fileident_bh fibh;
714
        int err;
715
        struct fileIdentDesc cfi, *fi;
716
 
717
        err = -EMLINK;
718
        if (dir->i_nlink >= (256<<sizeof(dir->i_nlink))-1)
719
                goto out;
720
 
721
        err = -EIO;
722
        inode = udf_new_inode(dir, S_IFDIR, &err);
723
        if (!inode)
724
                goto out;
725
 
726
        inode->i_op = &udf_dir_inode_operations;
727
        inode->i_fop = &udf_dir_operations;
728
        if (!(fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err)))
729
        {
730
                inode->i_nlink--;
731
                mark_inode_dirty(inode);
732
                iput(inode);
733
                goto out;
734
        }
735
        inode->i_nlink = 2;
736
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
737
        cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(dir));
738
        *(uint32_t *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
739
                cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL);
740
        cfi.fileCharacteristics = FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
741
        udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
742
        udf_release_data(fibh.sbh);
743
        inode->i_mode = S_IFDIR | mode;
744
        if (dir->i_mode & S_ISGID)
745
                inode->i_mode |= S_ISGID;
746
        mark_inode_dirty(inode);
747
 
748
        if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
749
        {
750
                inode->i_nlink = 0;
751
                mark_inode_dirty(inode);
752
                iput(inode);
753
                goto out;
754
        }
755
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
756
        cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
757
        *(uint32_t *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
758
                cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
759
        cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
760
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
761
        dir->i_version = ++event;
762
        dir->i_nlink++;
763
        mark_inode_dirty(dir);
764
        d_instantiate(dentry, inode);
765
        if (fibh.sbh != fibh.ebh)
766
                udf_release_data(fibh.ebh);
767
        udf_release_data(fibh.sbh);
768
        err = 0;
769
out:
770
        return err;
771
}
772
 
773
static int empty_dir(struct inode *dir)
774
{
775
        struct fileIdentDesc *fi, cfi;
776
        struct udf_fileident_bh fibh;
777
        loff_t f_pos;
778
        loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
779
        int block;
780
        lb_addr bloc, eloc;
781
        uint32_t extoffset, elen, offset;
782
        struct buffer_head *bh = NULL;
783
 
784
        f_pos = (udf_ext0_offset(dir) >> 2);
785
 
786
        fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
787
        if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
788
                &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
789
        {
790
                offset >>= dir->i_sb->s_blocksize_bits;
791
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
792
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
793
                {
794
                        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
795
                                extoffset -= sizeof(short_ad);
796
                        else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
797
                                extoffset -= sizeof(long_ad);
798
                }
799
                else
800
                        offset = 0;
801
        }
802
        else
803
        {
804
                udf_release_data(bh);
805
                return 0;
806
        }
807
 
808
        if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
809
                return 0;
810
 
811
        while ( (f_pos < size) )
812
        {
813
                fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
814
 
815
                if (!fi)
816
                {
817
                        if (fibh.sbh != fibh.ebh)
818
                                udf_release_data(fibh.ebh);
819
                        udf_release_data(fibh.sbh);
820
                        udf_release_data(bh);
821
                        return 0;
822
                }
823
 
824
                if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0)
825
                {
826
                        udf_release_data(bh);
827
                        return 0;
828
                }
829
        }
830
        if (fibh.sbh != fibh.ebh)
831
                udf_release_data(fibh.ebh);
832
        udf_release_data(fibh.sbh);
833
        udf_release_data(bh);
834
        return 1;
835
}
836
 
837
static int udf_rmdir(struct inode * dir, struct dentry * dentry)
838
{
839
        int retval;
840
        struct inode * inode = dentry->d_inode;
841
        struct udf_fileident_bh fibh;
842
        struct fileIdentDesc *fi, cfi;
843
 
844
        retval = -ENOENT;
845
        fi = udf_find_entry(dir, dentry, &fibh, &cfi);
846
        if (!fi)
847
                goto out;
848
 
849
        retval = -EIO;
850
        if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) != inode->i_ino)
851
                goto end_rmdir;
852
        retval = -ENOTEMPTY;
853
        if (!empty_dir(inode))
854
                goto end_rmdir;
855
        retval = udf_delete_entry(dir, fi, &fibh, &cfi);
856
        dir->i_version = ++event;
857
        if (retval)
858
                goto end_rmdir;
859
        if (inode->i_nlink != 2)
860
                udf_warning(inode->i_sb, "udf_rmdir",
861
                        "empty directory has nlink != 2 (%d)",
862
                        inode->i_nlink);
863
        inode->i_version = ++event;
864
        inode->i_nlink = 0;
865
        inode->i_size = 0;
866
        mark_inode_dirty(inode);
867
        dir->i_nlink --;
868
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
869
        UDF_I_UCTIME(inode) = UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME;
870
        mark_inode_dirty(dir);
871
 
872
end_rmdir:
873
        if (fibh.sbh != fibh.ebh)
874
                udf_release_data(fibh.ebh);
875
        udf_release_data(fibh.sbh);
876
out:
877
        return retval;
878
}
879
 
880
static int udf_unlink(struct inode * dir, struct dentry * dentry)
881
{
882
        int retval;
883
        struct inode * inode = dentry->d_inode;
884
        struct udf_fileident_bh fibh;
885
        struct fileIdentDesc *fi;
886
        struct fileIdentDesc cfi;
887
 
888
        retval = -ENOENT;
889
        fi = udf_find_entry(dir, dentry, &fibh, &cfi);
890
        if (!fi)
891
                goto out;
892
 
893
        retval = -EIO;
894
 
895
        if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) !=
896
                inode->i_ino)
897
        {
898
                goto end_unlink;
899
        }
900
 
901
        if (!inode->i_nlink)
902
        {
903
                udf_debug("Deleting nonexistent file (%lu), %d\n",
904
                        inode->i_ino, inode->i_nlink);
905
                inode->i_nlink = 1;
906
        }
907
        retval = udf_delete_entry(dir, fi, &fibh, &cfi);
908
        if (retval)
909
                goto end_unlink;
910
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
911
        UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME;
912
        mark_inode_dirty(dir);
913
        inode->i_nlink--;
914
        mark_inode_dirty(inode);
915
        inode->i_ctime = dir->i_ctime;
916
        retval = 0;
917
 
918
end_unlink:
919
        if (fibh.sbh != fibh.ebh)
920
                udf_release_data(fibh.ebh);
921
        udf_release_data(fibh.sbh);
922
out:
923
        return retval;
924
}
925
 
926
static int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname)
927
{
928
        struct inode * inode;
929
        struct pathComponent *pc;
930
        char *compstart;
931
        struct udf_fileident_bh fibh;
932
        struct buffer_head *bh = NULL;
933
        int eoffset, elen = 0;
934
        struct fileIdentDesc *fi;
935
        struct fileIdentDesc cfi;
936
        char *ea;
937
        int err;
938
        int block;
939
 
940
        if (!(inode = udf_new_inode(dir, S_IFLNK, &err)))
941
                goto out;
942
 
943
        inode->i_mode = S_IFLNK | S_IRWXUGO;
944
        inode->i_data.a_ops = &udf_symlink_aops;
945
        inode->i_op = &page_symlink_inode_operations;
946
 
947
        if (UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB)
948
        {
949
                struct buffer_head *bh = NULL;
950
                lb_addr bloc, eloc;
951
                uint32_t elen, extoffset;
952
 
953
                block = udf_new_block(inode->i_sb, inode,
954
                        UDF_I_LOCATION(inode).partitionReferenceNum,
955
                        UDF_I_LOCATION(inode).logicalBlockNum, &err);
956
                if (!block)
957
                        goto out_no_entry;
958
                bloc = UDF_I_LOCATION(inode);
959
                eloc.logicalBlockNum = block;
960
                eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
961
                elen = inode->i_sb->s_blocksize;
962
                UDF_I_LENEXTENTS(inode) = elen;
963
                extoffset = udf_file_entry_alloc_offset(inode);
964
                udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 0);
965
                udf_release_data(bh);
966
 
967
                block = udf_get_pblock(inode->i_sb, block,
968
                        UDF_I_LOCATION(inode).partitionReferenceNum, 0);
969
                bh = udf_tread(inode->i_sb, block);
970
                lock_buffer(bh);
971
                memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
972
                mark_buffer_uptodate(bh, 1);
973
                unlock_buffer(bh);
974
                mark_buffer_dirty_inode(bh, inode);
975
        }
976
        else
977
        {
978
                block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
979
                bh = udf_tread(inode->i_sb, block);
980
        }
981
        ea = bh->b_data + udf_ext0_offset(inode);
982
 
983
        eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
984
        pc = (struct pathComponent *)ea;
985
 
986
        if (*symname == '/')
987
        {
988
                do
989
                {
990
                        symname++;
991
                } while (*symname == '/');
992
 
993
                pc->componentType = 1;
994
                pc->lengthComponentIdent = 0;
995
                pc->componentFileVersionNum = 0;
996
                pc += sizeof(struct pathComponent);
997
                elen += sizeof(struct pathComponent);
998
        }
999
 
1000
        err = -ENAMETOOLONG;
1001
 
1002
        while (*symname)
1003
        {
1004
                if (elen + sizeof(struct pathComponent) > eoffset)
1005
                        goto out_no_entry;
1006
 
1007
                pc = (struct pathComponent *)(ea + elen);
1008
 
1009
                compstart = (char *)symname;
1010
 
1011
                do
1012
                {
1013
                        symname++;
1014
                } while (*symname && *symname != '/');
1015
 
1016
                pc->componentType = 5;
1017
                pc->lengthComponentIdent = 0;
1018
                pc->componentFileVersionNum = 0;
1019
                if (pc->componentIdent[0] == '.')
1020
                {
1021
                        if (pc->lengthComponentIdent == 1)
1022
                                pc->componentType = 4;
1023
                        else if (pc->lengthComponentIdent == 2 && pc->componentIdent[1] == '.')
1024
                                pc->componentType = 3;
1025
                }
1026
 
1027
                if (pc->componentType == 5)
1028
                {
1029
                        if (elen + sizeof(struct pathComponent) + symname - compstart > eoffset)
1030
                                goto out_no_entry;
1031
                        else
1032
                                pc->lengthComponentIdent = symname - compstart;
1033
 
1034
                        memcpy(pc->componentIdent, compstart, pc->lengthComponentIdent);
1035
                }
1036
 
1037
                elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
1038
 
1039
                if (*symname)
1040
                {
1041
                        do
1042
                        {
1043
                                symname++;
1044
                        } while (*symname == '/');
1045
                }
1046
        }
1047
 
1048
        udf_release_data(bh);
1049
        inode->i_size = elen;
1050
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
1051
                UDF_I_LENALLOC(inode) = inode->i_size;
1052
        mark_inode_dirty(inode);
1053
 
1054
        if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
1055
                goto out_no_entry;
1056
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
1057
        cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
1058
        if (UDF_SB_LVIDBH(inode->i_sb))
1059
        {
1060
                struct logicalVolHeaderDesc *lvhd;
1061
                uint64_t uniqueID;
1062
                lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
1063
                uniqueID = le64_to_cpu(lvhd->uniqueID);
1064
                *(uint32_t *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
1065
                        cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
1066
                if (!(++uniqueID & 0x00000000FFFFFFFFUL))
1067
                        uniqueID += 16;
1068
                lvhd->uniqueID = cpu_to_le64(uniqueID);
1069
                mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
1070
        }
1071
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
1072
        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
1073
        {
1074
                mark_inode_dirty(dir);
1075
                dir->i_version = ++event;
1076
        }
1077
        if (fibh.sbh != fibh.ebh)
1078
                udf_release_data(fibh.ebh);
1079
        udf_release_data(fibh.sbh);
1080
        d_instantiate(dentry, inode);
1081
        err = 0;
1082
 
1083
out:
1084
        return err;
1085
 
1086
out_no_entry:
1087
        inode->i_nlink--;
1088
        mark_inode_dirty(inode);
1089
        iput(inode);
1090
        goto out;
1091
}
1092
 
1093
static int udf_link(struct dentry * old_dentry, struct inode * dir,
1094
         struct dentry *dentry)
1095
{
1096
        struct inode *inode = old_dentry->d_inode;
1097
        struct udf_fileident_bh fibh;
1098
        int err;
1099
        struct fileIdentDesc cfi, *fi;
1100
 
1101
        if (S_ISDIR(inode->i_mode))
1102
                return -EPERM;
1103
 
1104
        if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1)
1105
                return -EMLINK;
1106
 
1107
        if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
1108
                return err;
1109
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
1110
        cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
1111
        if (UDF_SB_LVIDBH(inode->i_sb))
1112
        {
1113
                struct logicalVolHeaderDesc *lvhd;
1114
                uint64_t uniqueID;
1115
                lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
1116
                uniqueID = le64_to_cpu(lvhd->uniqueID);
1117
                *(uint32_t *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
1118
                        cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
1119
                if (!(++uniqueID & 0x00000000FFFFFFFFUL))
1120
                        uniqueID += 16;
1121
                lvhd->uniqueID = cpu_to_le64(uniqueID);
1122
                mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
1123
        }
1124
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
1125
        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
1126
        {
1127
                mark_inode_dirty(dir);
1128
                dir->i_version = ++event;
1129
        }
1130
        if (fibh.sbh != fibh.ebh)
1131
                udf_release_data(fibh.ebh);
1132
        udf_release_data(fibh.sbh);
1133
        inode->i_nlink ++;
1134
        inode->i_ctime = CURRENT_TIME;
1135
        UDF_I_UCTIME(inode) = CURRENT_UTIME;
1136
        mark_inode_dirty(inode);
1137
        atomic_inc(&inode->i_count);
1138
        d_instantiate(dentry, inode);
1139
        return 0;
1140
}
1141
 
1142
/* Anybody can rename anything with this: the permission checks are left to the
1143
 * higher-level routines.
1144
 */
1145
static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
1146
        struct inode * new_dir, struct dentry * new_dentry)
1147
{
1148
        struct inode * old_inode = old_dentry->d_inode;
1149
        struct inode * new_inode = new_dentry->d_inode;
1150
        struct udf_fileident_bh ofibh, nfibh;
1151
        struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi;
1152
        struct buffer_head *dir_bh = NULL;
1153
        int retval = -ENOENT;
1154
 
1155
        if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi)))
1156
        {
1157
                if (ofibh.sbh != ofibh.ebh)
1158
                        udf_release_data(ofibh.ebh);
1159
                udf_release_data(ofibh.sbh);
1160
        }
1161
        if (!ofi || udf_get_lb_pblock(old_dir->i_sb, lelb_to_cpu(ocfi.icb.extLocation), 0) !=
1162
                old_inode->i_ino)
1163
        {
1164
                goto end_rename;
1165
        }
1166
 
1167
        nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
1168
        if (nfi)
1169
        {
1170
                if (!new_inode)
1171
                {
1172
                        if (nfibh.sbh != nfibh.ebh)
1173
                                udf_release_data(nfibh.ebh);
1174
                        udf_release_data(nfibh.sbh);
1175
                        nfi = NULL;
1176
                }
1177
        }
1178
        if (S_ISDIR(old_inode->i_mode))
1179
        {
1180
                uint32_t offset = udf_ext0_offset(old_inode);
1181
 
1182
                if (new_inode)
1183
                {
1184
                        retval = -ENOTEMPTY;
1185
                        if (!empty_dir(new_inode))
1186
                                goto end_rename;
1187
                }
1188
                retval = -EIO;
1189
                dir_bh = udf_bread(old_inode, 0, 0, &retval);
1190
                if (!dir_bh)
1191
                        goto end_rename;
1192
                dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset);
1193
                if (!dir_fi)
1194
                        goto end_rename;
1195
                if (udf_get_lb_pblock(old_inode->i_sb, cpu_to_lelb(dir_fi->icb.extLocation), 0) !=
1196
                        old_dir->i_ino)
1197
                {
1198
                        goto end_rename;
1199
                }
1200
                retval = -EMLINK;
1201
                if (!new_inode && new_dir->i_nlink >= (256<<sizeof(new_dir->i_nlink))-1)
1202
                        goto end_rename;
1203
        }
1204
        if (!nfi)
1205
        {
1206
                nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval);
1207
                if (!nfi)
1208
                        goto end_rename;
1209
        }
1210
        new_dir->i_version = ++event;
1211
 
1212
        /*
1213
         * Like most other Unix systems, set the ctime for inodes on a
1214
         * rename.
1215
         */
1216
        old_inode->i_ctime = CURRENT_TIME;
1217
        UDF_I_UCTIME(old_inode) = CURRENT_UTIME;
1218
        mark_inode_dirty(old_inode);
1219
 
1220
        /*
1221
         * ok, that's it
1222
         */
1223
        ncfi.fileVersionNum = ocfi.fileVersionNum;
1224
        ncfi.fileCharacteristics = ocfi.fileCharacteristics;
1225
        memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad));
1226
        udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL);
1227
 
1228
        /* The old fid may have moved - find it again */
1229
        ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
1230
        udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
1231
 
1232
        old_dir->i_version = ++event;
1233
        if (new_inode)
1234
        {
1235
                new_inode->i_nlink--;
1236
                new_inode->i_ctime = CURRENT_TIME;
1237
                UDF_I_UCTIME(new_inode) = CURRENT_UTIME;
1238
                mark_inode_dirty(new_inode);
1239
        }
1240
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
1241
        UDF_I_UCTIME(old_dir) = UDF_I_UMTIME(old_dir) = CURRENT_UTIME;
1242
        mark_inode_dirty(old_dir);
1243
 
1244
        if (dir_bh)
1245
        {
1246
                dir_fi->icb.extLocation = lelb_to_cpu(UDF_I_LOCATION(new_dir));
1247
                udf_update_tag((char *)dir_fi, (sizeof(struct fileIdentDesc) +
1248
                        cpu_to_le16(dir_fi->lengthOfImpUse) + 3) & ~3);
1249
                if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB)
1250
                {
1251
                        old_inode->i_version = ++event;
1252
                        mark_inode_dirty(old_inode);
1253
                }
1254
                else
1255
                        mark_buffer_dirty_inode(dir_bh, old_inode);
1256
                old_dir->i_nlink --;
1257
                mark_inode_dirty(old_dir);
1258
                if (new_inode)
1259
                {
1260
                        new_inode->i_nlink --;
1261
                        mark_inode_dirty(new_inode);
1262
                }
1263
                else
1264
                {
1265
                        new_dir->i_nlink ++;
1266
                        mark_inode_dirty(new_dir);
1267
                }
1268
        }
1269
 
1270
        if (ofi)
1271
        {
1272
                if (ofibh.sbh != ofibh.ebh)
1273
                        udf_release_data(ofibh.ebh);
1274
                udf_release_data(ofibh.sbh);
1275
        }
1276
 
1277
        retval = 0;
1278
 
1279
end_rename:
1280
        udf_release_data(dir_bh);
1281
        if (nfi)
1282
        {
1283
                if (nfibh.sbh != nfibh.ebh)
1284
                        udf_release_data(nfibh.ebh);
1285
                udf_release_data(nfibh.sbh);
1286
        }
1287
        return retval;
1288
}
1289
 
1290
struct inode_operations udf_dir_inode_operations = {
1291
        lookup:                         udf_lookup,
1292
        create:                         udf_create,
1293
        link:                           udf_link,
1294
        unlink:                         udf_unlink,
1295
        symlink:                        udf_symlink,
1296
        mkdir:                          udf_mkdir,
1297
        rmdir:                          udf_rmdir,
1298
        mknod:                          udf_mknod,
1299
        rename:                         udf_rename,
1300
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.