blob: 2b34c8ca6c83ed2e6aa01f955664ffccf7eb1ec0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * namei.c
3 *
4 * PURPOSE
5 * Inode name handling routines for the OSTA-UDF(tm) filesystem.
6 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * COPYRIGHT
8 * This file is distributed under the terms of the GNU General Public
9 * License (GPL). Copies of the GPL can be obtained from:
10 * ftp://prep.ai.mit.edu/pub/gnu/GPL
11 * Each contributing author retains all rights to their own work.
12 *
13 * (C) 1998-2004 Ben Fennema
14 * (C) 1999-2000 Stelias Computing Inc
15 *
16 * HISTORY
17 *
18 * 12/12/98 blf Created. Split out the lookup code from dir.c
19 * 04/19/99 blf link, mknod, symlink support
20 */
21
22#include "udfdecl.h"
23
24#include "udf_i.h"
25#include "udf_sb.h"
26#include <linux/string.h>
27#include <linux/errno.h>
28#include <linux/mm.h>
29#include <linux/slab.h>
30#include <linux/quotaops.h>
31#include <linux/smp_lock.h>
32#include <linux/buffer_head.h>
Alexey Dobriyane8edc6e2007-05-21 01:22:52 +040033#include <linux/sched.h>
Bob Copelandf845fce2008-04-17 09:47:48 +020034#include <linux/crc-itu-t.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -070036static inline int udf_match(int len1, const char *name1, int len2,
37 const char *name2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070038{
39 if (len1 != len2)
40 return 0;
Cyrill Gorcunov28de7942007-07-21 04:37:18 -070041
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 return !memcmp(name1, name2, len1);
43}
44
45int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -070046 struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
Marcin Slusarz4b111112008-02-08 04:20:36 -080047 uint8_t *impuse, uint8_t *fileident)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048{
49 uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
50 uint16_t crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 int offset;
52 uint16_t liu = le16_to_cpu(cfi->lengthOfImpUse);
53 uint8_t lfi = cfi->lengthFileIdent;
54 int padlen = fibh->eoffset - fibh->soffset - liu - lfi -
Cyrill Gorcunov28de7942007-07-21 04:37:18 -070055 sizeof(struct fileIdentDesc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 int adinicb = 0;
57
Marcin Slusarzc0b34432008-02-08 04:20:42 -080058 if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 adinicb = 1;
60
61 offset = fibh->soffset + sizeof(struct fileIdentDesc);
62
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -070063 if (impuse) {
Cyrill Gorcunov28de7942007-07-21 04:37:18 -070064 if (adinicb || (offset + liu < 0)) {
65 memcpy((uint8_t *)sfi->impUse, impuse, liu);
66 } else if (offset >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 memcpy(fibh->ebh->b_data + offset, impuse, liu);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -070068 } else {
69 memcpy((uint8_t *)sfi->impUse, impuse, -offset);
Marcin Slusarz4b111112008-02-08 04:20:36 -080070 memcpy(fibh->ebh->b_data, impuse - offset,
71 liu + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 }
73 }
74
75 offset += liu;
76
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -070077 if (fileident) {
Cyrill Gorcunov28de7942007-07-21 04:37:18 -070078 if (adinicb || (offset + lfi < 0)) {
79 memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi);
80 } else if (offset >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 memcpy(fibh->ebh->b_data + offset, fileident, lfi);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -070082 } else {
Marcin Slusarz4b111112008-02-08 04:20:36 -080083 memcpy((uint8_t *)sfi->fileIdent + liu, fileident,
84 -offset);
85 memcpy(fibh->ebh->b_data, fileident - offset,
86 lfi + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 }
88 }
89
90 offset += lfi;
91
Cyrill Gorcunov28de7942007-07-21 04:37:18 -070092 if (adinicb || (offset + padlen < 0)) {
93 memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen);
94 } else if (offset >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 memset(fibh->ebh->b_data + offset, 0x00, padlen);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -070096 } else {
97 memset((uint8_t *)sfi->padding + liu + lfi, 0x00, -offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 memset(fibh->ebh->b_data, 0x00, padlen + offset);
99 }
100
Bob Copelandf845fce2008-04-17 09:47:48 +0200101 crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(tag),
102 sizeof(struct fileIdentDesc) - sizeof(tag));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700104 if (fibh->sbh == fibh->ebh) {
Bob Copelandf845fce2008-04-17 09:47:48 +0200105 crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
Marcin Slusarz4b111112008-02-08 04:20:36 -0800106 crclen + sizeof(tag) -
Bob Copelandf845fce2008-04-17 09:47:48 +0200107 sizeof(struct fileIdentDesc));
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700108 } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
Bob Copelandf845fce2008-04-17 09:47:48 +0200109 crc = crc_itu_t(crc, fibh->ebh->b_data +
Marcin Slusarz4b111112008-02-08 04:20:36 -0800110 sizeof(struct fileIdentDesc) +
111 fibh->soffset,
112 crclen + sizeof(tag) -
Bob Copelandf845fce2008-04-17 09:47:48 +0200113 sizeof(struct fileIdentDesc));
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700114 } else {
Bob Copelandf845fce2008-04-17 09:47:48 +0200115 crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
116 -fibh->soffset - sizeof(struct fileIdentDesc));
117 crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 }
119
120 cfi->descTag.descCRC = cpu_to_le16(crc);
121 cfi->descTag.descCRCLength = cpu_to_le16(crclen);
Marcin Slusarz3f2587b2008-02-08 04:20:39 -0800122 cfi->descTag.tagChecksum = udf_tag_checksum(&cfi->descTag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700124 if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset)) {
Marcin Slusarz4b111112008-02-08 04:20:36 -0800125 memcpy((uint8_t *)sfi, (uint8_t *)cfi,
126 sizeof(struct fileIdentDesc));
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700127 } else {
128 memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset);
129 memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset,
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700130 sizeof(struct fileIdentDesc) + fibh->soffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 }
132
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700133 if (adinicb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 mark_inode_dirty(inode);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700135 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 if (fibh->sbh != fibh->ebh)
137 mark_buffer_dirty_inode(fibh->ebh, inode);
138 mark_buffer_dirty_inode(fibh->sbh, inode);
139 }
140 return 0;
141}
142
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700143static struct fileIdentDesc *udf_find_entry(struct inode *dir,
144 struct dentry *dentry,
145 struct udf_fileident_bh *fibh,
146 struct fileIdentDesc *cfi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700148 struct fileIdentDesc *fi = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 loff_t f_pos;
150 int block, flen;
Jan Karab80697c2008-03-04 14:14:05 +0100151 char *fname = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 char *nameptr;
153 uint8_t lfi;
154 uint16_t liu;
KAMBAROV, ZAURec471dc2005-06-28 20:45:10 -0700155 loff_t size;
Jan Karaff116fc2007-05-08 00:35:14 -0700156 kernel_lb_addr eloc;
157 uint32_t elen;
Jan Kara60448b12007-05-08 00:35:13 -0700158 sector_t offset;
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700159 struct extent_position epos = {};
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800160 struct udf_inode_info *dinfo = UDF_I(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Jan Karaaf793292008-02-08 04:20:50 -0800162 size = udf_ext0_offset(dir) + dir->i_size;
163 f_pos = udf_ext0_offset(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Jan Karab80697c2008-03-04 14:14:05 +0100165 fibh->sbh = fibh->ebh = NULL;
Jan Karaaf793292008-02-08 04:20:50 -0800166 fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
Jan Karab80697c2008-03-04 14:14:05 +0100167 if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
168 if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
169 &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30))
170 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700172 if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800173 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
Jan Karaff116fc2007-05-08 00:35:14 -0700174 epos.offset -= sizeof(short_ad);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800175 else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
Jan Karaff116fc2007-05-08 00:35:14 -0700176 epos.offset -= sizeof(long_ad);
Marcin Slusarz4b111112008-02-08 04:20:36 -0800177 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 offset = 0;
179
Marcin Slusarz4b111112008-02-08 04:20:36 -0800180 fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
Jan Karab80697c2008-03-04 14:14:05 +0100181 if (!fibh->sbh)
182 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 }
184
Jan Karab80697c2008-03-04 14:14:05 +0100185 fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
186 if (!fname)
187 goto out_err;
188
Jan Karaaf793292008-02-08 04:20:50 -0800189 while (f_pos < size) {
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700190 fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
191 &elen, &offset);
Jan Karab80697c2008-03-04 14:14:05 +0100192 if (!fi)
193 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195 liu = le16_to_cpu(cfi->lengthOfImpUse);
196 lfi = cfi->lengthFileIdent;
197
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700198 if (fibh->sbh == fibh->ebh) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 nameptr = fi->fileIdent + liu;
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700200 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 int poffset; /* Unpaded ending offset */
202
Marcin Slusarz4b111112008-02-08 04:20:36 -0800203 poffset = fibh->soffset + sizeof(struct fileIdentDesc) +
204 liu + lfi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Marcin Slusarz4b111112008-02-08 04:20:36 -0800206 if (poffset >= lfi)
207 nameptr = (uint8_t *)(fibh->ebh->b_data +
208 poffset - lfi);
209 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 nameptr = fname;
Marcin Slusarz4b111112008-02-08 04:20:36 -0800211 memcpy(nameptr, fi->fileIdent + liu,
212 lfi - poffset);
213 memcpy(nameptr + lfi - poffset,
214 fibh->ebh->b_data, poffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 }
216 }
217
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700218 if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
219 if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 continue;
221 }
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700222
223 if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
224 if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 continue;
226 }
227
228 if (!lfi)
229 continue;
230
Marcin Slusarz4b111112008-02-08 04:20:36 -0800231 flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
232 if (flen && udf_match(flen, fname, dentry->d_name.len,
Jan Karab80697c2008-03-04 14:14:05 +0100233 dentry->d_name.name))
234 goto out_ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 }
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700236
Jan Karab80697c2008-03-04 14:14:05 +0100237out_err:
238 fi = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 if (fibh->sbh != fibh->ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700240 brelse(fibh->ebh);
241 brelse(fibh->sbh);
Jan Karab80697c2008-03-04 14:14:05 +0100242out_ok:
Jan Kara3bf25cb2007-05-08 00:35:16 -0700243 brelse(epos.bh);
Jan Karab80697c2008-03-04 14:14:05 +0100244 kfree(fname);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700245
Jan Karab80697c2008-03-04 14:14:05 +0100246 return fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
248
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700249static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
250 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251{
252 struct inode *inode = NULL;
Jayachandran Cdb9a3692006-02-03 03:04:50 -0800253 struct fileIdentDesc cfi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 struct udf_fileident_bh fibh;
255
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700256 if (dentry->d_name.len > UDF_NAME_LEN - 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 return ERR_PTR(-ENAMETOOLONG);
258
259 lock_kernel();
260#ifdef UDF_RECOVERY
261 /* temporary shorthand for specifying files by inode number */
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700262 if (!strncmp(dentry->d_name.name, ".B=", 3)) {
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700263 kernel_lb_addr lb = {
264 .logicalBlockNum = 0,
Marcin Slusarz4b111112008-02-08 04:20:36 -0800265 .partitionReferenceNum =
266 simple_strtoul(dentry->d_name.name + 3,
267 NULL, 0),
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700268 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 inode = udf_iget(dir->i_sb, lb);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700270 if (!inode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 unlock_kernel();
272 return ERR_PTR(-EACCES);
273 }
Marcin Slusarz4b111112008-02-08 04:20:36 -0800274 } else
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700275#endif /* UDF_RECOVERY */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700277 if (udf_find_entry(dir, dentry, &fibh, &cfi)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700279 brelse(fibh.ebh);
280 brelse(fibh.sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282 inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700283 if (!inode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 unlock_kernel();
285 return ERR_PTR(-EACCES);
286 }
287 }
288 unlock_kernel();
289 d_add(dentry, inode);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 return NULL;
292}
293
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700294static struct fileIdentDesc *udf_add_entry(struct inode *dir,
295 struct dentry *dentry,
296 struct udf_fileident_bh *fibh,
297 struct fileIdentDesc *cfi, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
Marcin Slusarz6c79e982008-02-08 04:20:30 -0800299 struct super_block *sb = dir->i_sb;
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700300 struct fileIdentDesc *fi = NULL;
Jan Karab80697c2008-03-04 14:14:05 +0100301 char *name = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 int namelen;
303 loff_t f_pos;
Jan Karaaf793292008-02-08 04:20:50 -0800304 loff_t size = udf_ext0_offset(dir) + dir->i_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 int nfidlen;
306 uint8_t lfi;
307 uint16_t liu;
308 int block;
Jan Karaff116fc2007-05-08 00:35:14 -0700309 kernel_lb_addr eloc;
310 uint32_t elen;
Jan Kara60448b12007-05-08 00:35:13 -0700311 sector_t offset;
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700312 struct extent_position epos = {};
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800313 struct udf_inode_info *dinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Jan Karab80697c2008-03-04 14:14:05 +0100315 fibh->sbh = fibh->ebh = NULL;
316 name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
317 if (!name) {
318 *err = -ENOMEM;
319 goto out_err;
320 }
321
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700322 if (dentry) {
323 if (!dentry->d_name.len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 *err = -EINVAL;
Jan Karab80697c2008-03-04 14:14:05 +0100325 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 }
Marcin Slusarz4b111112008-02-08 04:20:36 -0800327 namelen = udf_put_filename(sb, dentry->d_name.name, name,
328 dentry->d_name.len);
329 if (!namelen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 *err = -ENAMETOOLONG;
Jan Karab80697c2008-03-04 14:14:05 +0100331 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 }
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700333 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 namelen = 0;
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
337 nfidlen = (sizeof(struct fileIdentDesc) + namelen + 3) & ~3;
338
Jan Karaaf793292008-02-08 04:20:50 -0800339 f_pos = udf_ext0_offset(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Jan Karaaf793292008-02-08 04:20:50 -0800341 fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800342 dinfo = UDF_I(dir);
Jan Karab80697c2008-03-04 14:14:05 +0100343 if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
344 if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
345 &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) {
346 block = udf_get_lb_pblock(dir->i_sb,
347 dinfo->i_location, 0);
348 fibh->soffset = fibh->eoffset = sb->s_blocksize;
349 goto add;
350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700352 if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800353 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
Jan Karaff116fc2007-05-08 00:35:14 -0700354 epos.offset -= sizeof(short_ad);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800355 else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
Jan Karaff116fc2007-05-08 00:35:14 -0700356 epos.offset -= sizeof(long_ad);
Marcin Slusarz4b111112008-02-08 04:20:36 -0800357 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 offset = 0;
359
Marcin Slusarz4b111112008-02-08 04:20:36 -0800360 fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
361 if (!fibh->sbh) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 *err = -EIO;
Jan Karab80697c2008-03-04 14:14:05 +0100363 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 }
365
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800366 block = dinfo->i_location.logicalBlockNum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 }
368
Jan Karaaf793292008-02-08 04:20:50 -0800369 while (f_pos < size) {
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700370 fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
371 &elen, &offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700373 if (!fi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 *err = -EIO;
Jan Karab80697c2008-03-04 14:14:05 +0100375 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 }
377
378 liu = le16_to_cpu(cfi->lengthOfImpUse);
379 lfi = cfi->lengthFileIdent;
380
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700381 if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
Marcin Slusarz4b111112008-02-08 04:20:36 -0800382 if (((sizeof(struct fileIdentDesc) +
383 liu + lfi + 3) & ~3) == nfidlen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 cfi->descTag.tagSerialNum = cpu_to_le16(1);
385 cfi->fileVersionNum = cpu_to_le16(1);
386 cfi->fileCharacteristics = 0;
387 cfi->lengthFileIdent = namelen;
388 cfi->lengthOfImpUse = cpu_to_le16(0);
Marcin Slusarz4b111112008-02-08 04:20:36 -0800389 if (!udf_write_fi(dir, cfi, fi, fibh, NULL,
390 name))
Jan Karab80697c2008-03-04 14:14:05 +0100391 goto out_ok;
Marcin Slusarz4b111112008-02-08 04:20:36 -0800392 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 *err = -EIO;
Jan Karab80697c2008-03-04 14:14:05 +0100394 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 }
396 }
397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 }
399
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700400add:
Jan Kara05343c42008-02-08 04:20:51 -0800401 if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
402 elen = (elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
403 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
404 epos.offset -= sizeof(short_ad);
405 else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
406 epos.offset -= sizeof(long_ad);
407 udf_write_aext(dir, &epos, eloc, elen, 1);
408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 f_pos += nfidlen;
410
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800411 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700412 sb->s_blocksize - fibh->eoffset < nfidlen) {
Jan Kara3bf25cb2007-05-08 00:35:16 -0700413 brelse(epos.bh);
Jan Karaff116fc2007-05-08 00:35:14 -0700414 epos.bh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 fibh->soffset -= udf_ext0_offset(dir);
416 fibh->eoffset -= udf_ext0_offset(dir);
Jan Karaaf793292008-02-08 04:20:50 -0800417 f_pos -= udf_ext0_offset(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 if (fibh->sbh != fibh->ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700419 brelse(fibh->ebh);
420 brelse(fibh->sbh);
Marcin Slusarz4b111112008-02-08 04:20:36 -0800421 fibh->sbh = fibh->ebh =
422 udf_expand_dir_adinicb(dir, &block, err);
423 if (!fibh->sbh)
Jan Karab80697c2008-03-04 14:14:05 +0100424 goto out_err;
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800425 epos.block = dinfo->i_location;
Jan Karaff116fc2007-05-08 00:35:14 -0700426 epos.offset = udf_file_entry_alloc_offset(dir);
Jan Kara05343c42008-02-08 04:20:51 -0800427 /* Load extent udf_expand_dir_adinicb() has created */
428 udf_current_aext(dir, &epos, &eloc, &elen, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 }
430
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700431 if (sb->s_blocksize - fibh->eoffset >= nfidlen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 fibh->soffset = fibh->eoffset;
433 fibh->eoffset += nfidlen;
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700434 if (fibh->sbh != fibh->ebh) {
Jan Kara3bf25cb2007-05-08 00:35:16 -0700435 brelse(fibh->sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 fibh->sbh = fibh->ebh;
437 }
438
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800439 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
440 block = dinfo->i_location.logicalBlockNum;
Marcin Slusarz4b111112008-02-08 04:20:36 -0800441 fi = (struct fileIdentDesc *)
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800442 (dinfo->i_ext.i_data +
Marcin Slusarzc0b34432008-02-08 04:20:42 -0800443 fibh->soffset -
Marcin Slusarz4b111112008-02-08 04:20:36 -0800444 udf_ext0_offset(dir) +
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800445 dinfo->i_lenEAttr);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700446 } else {
Marcin Slusarz4b111112008-02-08 04:20:36 -0800447 block = eloc.logicalBlockNum +
448 ((elen - 1) >>
449 dir->i_sb->s_blocksize_bits);
450 fi = (struct fileIdentDesc *)
451 (fibh->sbh->b_data + fibh->soffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 }
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700453 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 fibh->soffset = fibh->eoffset - sb->s_blocksize;
455 fibh->eoffset += nfidlen - sb->s_blocksize;
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700456 if (fibh->sbh != fibh->ebh) {
Jan Kara3bf25cb2007-05-08 00:35:16 -0700457 brelse(fibh->sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 fibh->sbh = fibh->ebh;
459 }
460
461 block = eloc.logicalBlockNum + ((elen - 1) >>
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700462 dir->i_sb->s_blocksize_bits);
Marcin Slusarz4b111112008-02-08 04:20:36 -0800463 fibh->ebh = udf_bread(dir,
Jan Karaaf793292008-02-08 04:20:50 -0800464 f_pos >> dir->i_sb->s_blocksize_bits, 1, err);
Jan Karab80697c2008-03-04 14:14:05 +0100465 if (!fibh->ebh)
466 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700468 if (!fibh->soffset) {
Jan Karaff116fc2007-05-08 00:35:14 -0700469 if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700470 (EXT_RECORDED_ALLOCATED >> 30)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 block = eloc.logicalBlockNum + ((elen - 1) >>
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700472 dir->i_sb->s_blocksize_bits);
Marcin Slusarz4b111112008-02-08 04:20:36 -0800473 } else
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700474 block++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Jan Kara3bf25cb2007-05-08 00:35:16 -0700476 brelse(fibh->sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 fibh->sbh = fibh->ebh;
478 fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700479 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 fi = (struct fileIdentDesc *)
Marcin Slusarz4b111112008-02-08 04:20:36 -0800481 (fibh->sbh->b_data + sb->s_blocksize +
482 fibh->soffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 }
484 }
485
486 memset(cfi, 0, sizeof(struct fileIdentDesc));
Marcin Slusarz6c79e982008-02-08 04:20:30 -0800487 if (UDF_SB(sb)->s_udfrev >= 0x0200)
Marcin Slusarz4b111112008-02-08 04:20:36 -0800488 udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block,
489 sizeof(tag));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 else
Marcin Slusarz4b111112008-02-08 04:20:36 -0800491 udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block,
492 sizeof(tag));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 cfi->fileVersionNum = cpu_to_le16(1);
494 cfi->lengthFileIdent = namelen;
495 cfi->lengthOfImpUse = cpu_to_le16(0);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700496 if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 dir->i_size += nfidlen;
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800498 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
499 dinfo->i_lenAlloc += nfidlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 mark_inode_dirty(dir);
Jan Karab80697c2008-03-04 14:14:05 +0100501 goto out_ok;
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700502 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 *err = -EIO;
Jan Karab80697c2008-03-04 14:14:05 +0100504 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 }
Jan Karab80697c2008-03-04 14:14:05 +0100506
507out_err:
508 fi = NULL;
509 if (fibh->sbh != fibh->ebh)
510 brelse(fibh->ebh);
511 brelse(fibh->sbh);
512out_ok:
513 brelse(epos.bh);
514 kfree(name);
515 return fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516}
517
518static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700519 struct udf_fileident_bh *fibh,
520 struct fileIdentDesc *cfi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
522 cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
525 memset(&(cfi->icb), 0x00, sizeof(long_ad));
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
528}
529
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700530static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
531 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532{
533 struct udf_fileident_bh fibh;
534 struct inode *inode;
535 struct fileIdentDesc cfi, *fi;
536 int err;
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800537 struct udf_inode_info *iinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 lock_kernel();
540 inode = udf_new_inode(dir, mode, &err);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700541 if (!inode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 unlock_kernel();
543 return err;
544 }
545
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800546 iinfo = UDF_I(inode);
547 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 inode->i_data.a_ops = &udf_adinicb_aops;
549 else
550 inode->i_data.a_ops = &udf_aops;
551 inode->i_op = &udf_file_inode_operations;
552 inode->i_fop = &udf_file_operations;
553 inode->i_mode = mode;
554 mark_inode_dirty(inode);
555
Marcin Slusarz4b111112008-02-08 04:20:36 -0800556 fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
557 if (!fi) {
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700558 inode->i_nlink--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 mark_inode_dirty(inode);
560 iput(inode);
561 unlock_kernel();
562 return err;
563 }
564 cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800565 cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700566 *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800567 cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
Marcin Slusarzc0b34432008-02-08 04:20:42 -0800569 if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 mark_inode_dirty(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700572 brelse(fibh.ebh);
573 brelse(fibh.sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 unlock_kernel();
575 d_instantiate(dentry, inode);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 return 0;
578}
579
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700580static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
581 dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582{
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700583 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 struct udf_fileident_bh fibh;
585 struct fileIdentDesc cfi, *fi;
586 int err;
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800587 struct udf_inode_info *iinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589 if (!old_valid_dev(rdev))
590 return -EINVAL;
591
592 lock_kernel();
593 err = -EIO;
594 inode = udf_new_inode(dir, mode, &err);
595 if (!inode)
596 goto out;
597
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800598 iinfo = UDF_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 inode->i_uid = current->fsuid;
600 init_special_inode(inode, mode, rdev);
Marcin Slusarz4b111112008-02-08 04:20:36 -0800601 fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
602 if (!fi) {
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700603 inode->i_nlink--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 mark_inode_dirty(inode);
605 iput(inode);
606 unlock_kernel();
607 return err;
608 }
609 cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800610 cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700611 *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800612 cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
Marcin Slusarzc0b34432008-02-08 04:20:42 -0800614 if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 mark_inode_dirty(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 mark_inode_dirty(inode);
617
618 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700619 brelse(fibh.ebh);
620 brelse(fibh.sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 d_instantiate(dentry, inode);
622 err = 0;
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700623
624out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 unlock_kernel();
626 return err;
627}
628
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700629static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700631 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 struct udf_fileident_bh fibh;
633 struct fileIdentDesc cfi, *fi;
634 int err;
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800635 struct udf_inode_info *dinfo = UDF_I(dir);
636 struct udf_inode_info *iinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638 lock_kernel();
639 err = -EMLINK;
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700640 if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 goto out;
642
643 err = -EIO;
644 inode = udf_new_inode(dir, S_IFDIR, &err);
645 if (!inode)
646 goto out;
647
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800648 iinfo = UDF_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 inode->i_op = &udf_dir_inode_operations;
650 inode->i_fop = &udf_dir_operations;
Marcin Slusarz4b111112008-02-08 04:20:36 -0800651 fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err);
652 if (!fi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 inode->i_nlink--;
654 mark_inode_dirty(inode);
655 iput(inode);
656 goto out;
657 }
658 inode->i_nlink = 2;
659 cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800660 cfi.icb.extLocation = cpu_to_lelb(dinfo->i_location);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700661 *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800662 cpu_to_le32(dinfo->i_unique & 0x00000000FFFFFFFFUL);
Marcin Slusarz4b111112008-02-08 04:20:36 -0800663 cfi.fileCharacteristics =
664 FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
Jan Kara3bf25cb2007-05-08 00:35:16 -0700666 brelse(fibh.sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 inode->i_mode = S_IFDIR | mode;
668 if (dir->i_mode & S_ISGID)
669 inode->i_mode |= S_ISGID;
670 mark_inode_dirty(inode);
671
Marcin Slusarz4b111112008-02-08 04:20:36 -0800672 fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
673 if (!fi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 inode->i_nlink = 0;
675 mark_inode_dirty(inode);
676 iput(inode);
677 goto out;
678 }
679 cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800680 cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700681 *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800682 cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
684 udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
Dave Hansend8c76e62006-09-30 23:29:04 -0700685 inc_nlink(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 mark_inode_dirty(dir);
687 d_instantiate(dentry, inode);
688 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700689 brelse(fibh.ebh);
690 brelse(fibh.sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 err = 0;
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700692
693out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 unlock_kernel();
695 return err;
696}
697
698static int empty_dir(struct inode *dir)
699{
700 struct fileIdentDesc *fi, cfi;
701 struct udf_fileident_bh fibh;
702 loff_t f_pos;
Jan Karaaf793292008-02-08 04:20:50 -0800703 loff_t size = udf_ext0_offset(dir) + dir->i_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 int block;
Jan Karaff116fc2007-05-08 00:35:14 -0700705 kernel_lb_addr eloc;
706 uint32_t elen;
Jan Kara60448b12007-05-08 00:35:13 -0700707 sector_t offset;
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700708 struct extent_position epos = {};
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800709 struct udf_inode_info *dinfo = UDF_I(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Jan Karaaf793292008-02-08 04:20:50 -0800711 f_pos = udf_ext0_offset(dir);
712 fibh.soffset = fibh.eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800714 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 fibh.sbh = fibh.ebh = NULL;
Jan Karaaf793292008-02-08 04:20:50 -0800716 else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits,
Marcin Slusarz4b111112008-02-08 04:20:36 -0800717 &epos, &eloc, &elen, &offset) ==
718 (EXT_RECORDED_ALLOCATED >> 30)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700720 if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800721 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
Jan Karaff116fc2007-05-08 00:35:14 -0700722 epos.offset -= sizeof(short_ad);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800723 else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
Jan Karaff116fc2007-05-08 00:35:14 -0700724 epos.offset -= sizeof(long_ad);
Marcin Slusarz4b111112008-02-08 04:20:36 -0800725 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 offset = 0;
727
Marcin Slusarz4b111112008-02-08 04:20:36 -0800728 fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block);
729 if (!fibh.sbh) {
Jan Kara3bf25cb2007-05-08 00:35:16 -0700730 brelse(epos.bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 return 0;
732 }
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700733 } else {
Jan Kara3bf25cb2007-05-08 00:35:16 -0700734 brelse(epos.bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 return 0;
736 }
737
Jan Karaaf793292008-02-08 04:20:50 -0800738 while (f_pos < size) {
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700739 fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc,
740 &elen, &offset);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700741 if (!fi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700743 brelse(fibh.ebh);
744 brelse(fibh.sbh);
745 brelse(epos.bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 return 0;
747 }
748
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700749 if (cfi.lengthFileIdent &&
750 (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700752 brelse(fibh.ebh);
753 brelse(fibh.sbh);
754 brelse(epos.bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 return 0;
756 }
757 }
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700760 brelse(fibh.ebh);
761 brelse(fibh.sbh);
762 brelse(epos.bh);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return 1;
765}
766
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700767static int udf_rmdir(struct inode *dir, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
769 int retval;
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700770 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 struct udf_fileident_bh fibh;
772 struct fileIdentDesc *fi, cfi;
773 kernel_lb_addr tloc;
774
775 retval = -ENOENT;
776 lock_kernel();
777 fi = udf_find_entry(dir, dentry, &fibh, &cfi);
778 if (!fi)
779 goto out;
780
781 retval = -EIO;
782 tloc = lelb_to_cpu(cfi.icb.extLocation);
783 if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino)
784 goto end_rmdir;
785 retval = -ENOTEMPTY;
786 if (!empty_dir(inode))
787 goto end_rmdir;
788 retval = udf_delete_entry(dir, fi, &fibh, &cfi);
789 if (retval)
790 goto end_rmdir;
791 if (inode->i_nlink != 2)
792 udf_warning(inode->i_sb, "udf_rmdir",
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700793 "empty directory has nlink != 2 (%d)",
794 inode->i_nlink);
Dave Hansence71ec32006-09-30 23:29:06 -0700795 clear_nlink(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 inode->i_size = 0;
Stephen Mollettc007c062007-05-08 00:31:31 -0700797 inode_dec_link_count(dir);
Marcin Slusarz4b111112008-02-08 04:20:36 -0800798 inode->i_ctime = dir->i_ctime = dir->i_mtime =
799 current_fs_time(dir->i_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 mark_inode_dirty(dir);
801
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700802end_rmdir:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700804 brelse(fibh.ebh);
805 brelse(fibh.sbh);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700806
807out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 unlock_kernel();
809 return retval;
810}
811
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700812static int udf_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
814 int retval;
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700815 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 struct udf_fileident_bh fibh;
817 struct fileIdentDesc *fi;
818 struct fileIdentDesc cfi;
819 kernel_lb_addr tloc;
820
821 retval = -ENOENT;
822 lock_kernel();
823 fi = udf_find_entry(dir, dentry, &fibh, &cfi);
824 if (!fi)
825 goto out;
826
827 retval = -EIO;
828 tloc = lelb_to_cpu(cfi.icb.extLocation);
829 if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino)
830 goto end_unlink;
831
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700832 if (!inode->i_nlink) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 udf_debug("Deleting nonexistent file (%lu), %d\n",
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700834 inode->i_ino, inode->i_nlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 inode->i_nlink = 1;
836 }
837 retval = udf_delete_entry(dir, fi, &fibh, &cfi);
838 if (retval)
839 goto end_unlink;
840 dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
841 mark_inode_dirty(dir);
Dave Hansen9a53c3a2006-09-30 23:29:03 -0700842 inode_dec_link_count(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 inode->i_ctime = dir->i_ctime;
844 retval = 0;
845
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700846end_unlink:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -0700848 brelse(fibh.ebh);
849 brelse(fibh.sbh);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700850
851out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 unlock_kernel();
853 return retval;
854}
855
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700856static int udf_symlink(struct inode *dir, struct dentry *dentry,
857 const char *symname)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858{
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700859 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 struct pathComponent *pc;
861 char *compstart;
862 struct udf_fileident_bh fibh;
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700863 struct extent_position epos = {};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 int eoffset, elen = 0;
865 struct fileIdentDesc *fi;
866 struct fileIdentDesc cfi;
867 char *ea;
868 int err;
869 int block;
Jan Karab80697c2008-03-04 14:14:05 +0100870 char *name = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 int namelen;
Marcin Slusarz6c79e982008-02-08 04:20:30 -0800872 struct buffer_head *bh;
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800873 struct udf_inode_info *iinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875 lock_kernel();
Marcin Slusarz4b111112008-02-08 04:20:36 -0800876 inode = udf_new_inode(dir, S_IFLNK, &err);
877 if (!inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 goto out;
879
Jan Karab80697c2008-03-04 14:14:05 +0100880 name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
881 if (!name) {
882 err = -ENOMEM;
883 goto out_no_entry;
884 }
885
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800886 iinfo = UDF_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 inode->i_mode = S_IFLNK | S_IRWXUGO;
888 inode->i_data.a_ops = &udf_symlink_aops;
889 inode->i_op = &page_symlink_inode_operations;
890
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800891 if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
Jan Karaff116fc2007-05-08 00:35:14 -0700892 kernel_lb_addr eloc;
Harvey Harrison78e917d2008-04-28 02:16:19 -0700893 uint32_t bsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
895 block = udf_new_block(inode->i_sb, inode,
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800896 iinfo->i_location.partitionReferenceNum,
897 iinfo->i_location.logicalBlockNum, &err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 if (!block)
899 goto out_no_entry;
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800900 epos.block = iinfo->i_location;
Jan Karaff116fc2007-05-08 00:35:14 -0700901 epos.offset = udf_file_entry_alloc_offset(inode);
902 epos.bh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 eloc.logicalBlockNum = block;
Marcin Slusarz4b111112008-02-08 04:20:36 -0800904 eloc.partitionReferenceNum =
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800905 iinfo->i_location.partitionReferenceNum;
Harvey Harrison78e917d2008-04-28 02:16:19 -0700906 bsize = inode->i_sb->s_blocksize;
907 iinfo->i_lenExtents = bsize;
908 udf_add_aext(inode, &epos, eloc, bsize, 0);
Jan Kara3bf25cb2007-05-08 00:35:16 -0700909 brelse(epos.bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911 block = udf_get_pblock(inode->i_sb, block,
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800912 iinfo->i_location.partitionReferenceNum,
Marcin Slusarz4b111112008-02-08 04:20:36 -0800913 0);
Jan Karaff116fc2007-05-08 00:35:14 -0700914 epos.bh = udf_tread(inode->i_sb, block);
915 lock_buffer(epos.bh);
916 memset(epos.bh->b_data, 0x00, inode->i_sb->s_blocksize);
917 set_buffer_uptodate(epos.bh);
918 unlock_buffer(epos.bh);
919 mark_buffer_dirty_inode(epos.bh, inode);
920 ea = epos.bh->b_data + udf_ext0_offset(inode);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800921 } else
922 ea = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
925 pc = (struct pathComponent *)ea;
926
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700927 if (*symname == '/') {
928 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 symname++;
930 } while (*symname == '/');
931
932 pc->componentType = 1;
933 pc->lengthComponentIdent = 0;
934 pc->componentFileVersionNum = 0;
935 pc += sizeof(struct pathComponent);
936 elen += sizeof(struct pathComponent);
937 }
938
939 err = -ENAMETOOLONG;
940
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700941 while (*symname) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 if (elen + sizeof(struct pathComponent) > eoffset)
943 goto out_no_entry;
944
945 pc = (struct pathComponent *)(ea + elen);
946
947 compstart = (char *)symname;
948
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700949 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 symname++;
951 } while (*symname && *symname != '/');
952
953 pc->componentType = 5;
954 pc->lengthComponentIdent = 0;
955 pc->componentFileVersionNum = 0;
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700956 if (compstart[0] == '.') {
957 if ((symname - compstart) == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 pc->componentType = 4;
Marcin Slusarz4b111112008-02-08 04:20:36 -0800959 else if ((symname - compstart) == 2 &&
960 compstart[1] == '.')
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 pc->componentType = 3;
962 }
963
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700964 if (pc->componentType == 5) {
Cyrill Gorcunov28de7942007-07-21 04:37:18 -0700965 namelen = udf_put_filename(inode->i_sb, compstart, name,
966 symname - compstart);
967 if (!namelen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 goto out_no_entry;
969
Marcin Slusarz4b111112008-02-08 04:20:36 -0800970 if (elen + sizeof(struct pathComponent) + namelen >
971 eoffset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 goto out_no_entry;
973 else
974 pc->lengthComponentIdent = namelen;
975
976 memcpy(pc->componentIdent, name, namelen);
977 }
978
979 elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
980
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -0700981 if (*symname) {
982 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 symname++;
984 } while (*symname == '/');
985 }
986 }
987
Jan Kara3bf25cb2007-05-08 00:35:16 -0700988 brelse(epos.bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 inode->i_size = elen;
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800990 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
991 iinfo->i_lenAlloc = inode->i_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 mark_inode_dirty(inode);
993
Marcin Slusarz4b111112008-02-08 04:20:36 -0800994 fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
995 if (!fi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 goto out_no_entry;
997 cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -0800998 cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
Marcin Slusarz6c79e982008-02-08 04:20:30 -0800999 bh = UDF_SB(inode->i_sb)->s_lvid_bh;
1000 if (bh) {
Marcin Slusarz4b111112008-02-08 04:20:36 -08001001 struct logicalVolIntegrityDesc *lvid =
1002 (struct logicalVolIntegrityDesc *)bh->b_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 struct logicalVolHeaderDesc *lvhd;
1004 uint64_t uniqueID;
Marcin Slusarz4b111112008-02-08 04:20:36 -08001005 lvhd = (struct logicalVolHeaderDesc *)
1006 lvid->logicalVolContentsUse;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 uniqueID = le64_to_cpu(lvhd->uniqueID);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -07001008 *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
1009 cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 if (!(++uniqueID & 0x00000000FFFFFFFFUL))
1011 uniqueID += 16;
1012 lvhd->uniqueID = cpu_to_le64(uniqueID);
Marcin Slusarz6c79e982008-02-08 04:20:30 -08001013 mark_buffer_dirty(bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 }
1015 udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
Marcin Slusarzc0b34432008-02-08 04:20:42 -08001016 if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 mark_inode_dirty(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -07001019 brelse(fibh.ebh);
1020 brelse(fibh.sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 d_instantiate(dentry, inode);
1022 err = 0;
1023
Cyrill Gorcunov28de7942007-07-21 04:37:18 -07001024out:
Jan Karab80697c2008-03-04 14:14:05 +01001025 kfree(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 unlock_kernel();
1027 return err;
1028
Cyrill Gorcunov28de7942007-07-21 04:37:18 -07001029out_no_entry:
Dave Hansen9a53c3a2006-09-30 23:29:03 -07001030 inode_dec_link_count(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 iput(inode);
1032 goto out;
1033}
1034
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001035static int udf_link(struct dentry *old_dentry, struct inode *dir,
1036 struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
1038 struct inode *inode = old_dentry->d_inode;
1039 struct udf_fileident_bh fibh;
1040 struct fileIdentDesc cfi, *fi;
1041 int err;
Marcin Slusarz6c79e982008-02-08 04:20:30 -08001042 struct buffer_head *bh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
1044 lock_kernel();
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001045 if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 unlock_kernel();
1047 return -EMLINK;
1048 }
1049
Marcin Slusarz4b111112008-02-08 04:20:36 -08001050 fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
1051 if (!fi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 unlock_kernel();
1053 return err;
1054 }
1055 cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
Marcin Slusarzc0b34432008-02-08 04:20:42 -08001056 cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
Marcin Slusarz6c79e982008-02-08 04:20:30 -08001057 bh = UDF_SB(inode->i_sb)->s_lvid_bh;
1058 if (bh) {
Marcin Slusarz4b111112008-02-08 04:20:36 -08001059 struct logicalVolIntegrityDesc *lvid =
1060 (struct logicalVolIntegrityDesc *)bh->b_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 struct logicalVolHeaderDesc *lvhd;
1062 uint64_t uniqueID;
Marcin Slusarz4b111112008-02-08 04:20:36 -08001063 lvhd = (struct logicalVolHeaderDesc *)
1064 (lvid->logicalVolContentsUse);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 uniqueID = le64_to_cpu(lvhd->uniqueID);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -07001066 *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
1067 cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if (!(++uniqueID & 0x00000000FFFFFFFFUL))
1069 uniqueID += 16;
1070 lvhd->uniqueID = cpu_to_le64(uniqueID);
Marcin Slusarz6c79e982008-02-08 04:20:30 -08001071 mark_buffer_dirty(bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 }
1073 udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
Marcin Slusarzc0b34432008-02-08 04:20:42 -08001074 if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 mark_inode_dirty(dir);
Cyrill Gorcunov28de7942007-07-21 04:37:18 -07001076
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 if (fibh.sbh != fibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -07001078 brelse(fibh.ebh);
1079 brelse(fibh.sbh);
Dave Hansend8c76e62006-09-30 23:29:04 -07001080 inc_nlink(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 inode->i_ctime = current_fs_time(inode->i_sb);
1082 mark_inode_dirty(inode);
1083 atomic_inc(&inode->i_count);
1084 d_instantiate(dentry, inode);
1085 unlock_kernel();
Cyrill Gorcunov28de7942007-07-21 04:37:18 -07001086
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 return 0;
1088}
1089
1090/* Anybody can rename anything with this: the permission checks are left to the
1091 * higher-level routines.
1092 */
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001093static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
1094 struct inode *new_dir, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095{
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001096 struct inode *old_inode = old_dentry->d_inode;
1097 struct inode *new_inode = new_dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 struct udf_fileident_bh ofibh, nfibh;
Marcin Slusarz4b111112008-02-08 04:20:36 -08001099 struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL;
1100 struct fileIdentDesc ocfi, ncfi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 struct buffer_head *dir_bh = NULL;
1102 int retval = -ENOENT;
1103 kernel_lb_addr tloc;
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -08001104 struct udf_inode_info *old_iinfo = UDF_I(old_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
1106 lock_kernel();
Marcin Slusarz4b111112008-02-08 04:20:36 -08001107 ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
1108 if (ofi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 if (ofibh.sbh != ofibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -07001110 brelse(ofibh.ebh);
1111 brelse(ofibh.sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 }
1113 tloc = lelb_to_cpu(ocfi.icb.extLocation);
1114 if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0)
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001115 != old_inode->i_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 goto end_rename;
1117
1118 nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001119 if (nfi) {
1120 if (!new_inode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 if (nfibh.sbh != nfibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -07001122 brelse(nfibh.ebh);
1123 brelse(nfibh.sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 nfi = NULL;
1125 }
1126 }
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001127 if (S_ISDIR(old_inode->i_mode)) {
Marcin Slusarz7f3fbd02008-02-08 04:20:49 -08001128 int offset = udf_ext0_offset(old_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001130 if (new_inode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 retval = -ENOTEMPTY;
1132 if (!empty_dir(new_inode))
1133 goto end_rename;
1134 }
1135 retval = -EIO;
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -08001136 if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
Marcin Slusarz4b111112008-02-08 04:20:36 -08001137 dir_fi = udf_get_fileident(
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -08001138 old_iinfo->i_ext.i_data -
1139 (old_iinfo->i_efe ?
Marcin Slusarz4b111112008-02-08 04:20:36 -08001140 sizeof(struct extendedFileEntry) :
1141 sizeof(struct fileEntry)),
1142 old_inode->i_sb->s_blocksize, &offset);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001143 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 dir_bh = udf_bread(old_inode, 0, 0, &retval);
1145 if (!dir_bh)
1146 goto end_rename;
Marcin Slusarz4b111112008-02-08 04:20:36 -08001147 dir_fi = udf_get_fileident(dir_bh->b_data,
1148 old_inode->i_sb->s_blocksize, &offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 }
1150 if (!dir_fi)
1151 goto end_rename;
1152 tloc = lelb_to_cpu(dir_fi->icb.extLocation);
Marcin Slusarz4b111112008-02-08 04:20:36 -08001153 if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0) !=
1154 old_dir->i_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 goto end_rename;
1156
1157 retval = -EMLINK;
Marcin Slusarz4b111112008-02-08 04:20:36 -08001158 if (!new_inode &&
1159 new_dir->i_nlink >=
1160 (256 << sizeof(new_dir->i_nlink)) - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 goto end_rename;
1162 }
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001163 if (!nfi) {
Marcin Slusarz4b111112008-02-08 04:20:36 -08001164 nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi,
1165 &retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 if (!nfi)
1167 goto end_rename;
1168 }
1169
1170 /*
1171 * Like most other Unix systems, set the ctime for inodes on a
1172 * rename.
1173 */
1174 old_inode->i_ctime = current_fs_time(old_inode->i_sb);
1175 mark_inode_dirty(old_inode);
1176
1177 /*
1178 * ok, that's it
1179 */
1180 ncfi.fileVersionNum = ocfi.fileVersionNum;
1181 ncfi.fileCharacteristics = ocfi.fileCharacteristics;
1182 memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad));
1183 udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL);
1184
1185 /* The old fid may have moved - find it again */
1186 ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
1187 udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
1188
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001189 if (new_inode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 new_inode->i_ctime = current_fs_time(new_inode->i_sb);
Dave Hansen9a53c3a2006-09-30 23:29:03 -07001191 inode_dec_link_count(new_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 }
1193 old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
1194 mark_inode_dirty(old_dir);
1195
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001196 if (dir_fi) {
Marcin Slusarzc0b34432008-02-08 04:20:42 -08001197 dir_fi->icb.extLocation = cpu_to_lelb(UDF_I(new_dir)->i_location);
Marcin Slusarz4b111112008-02-08 04:20:36 -08001198 udf_update_tag((char *)dir_fi,
1199 (sizeof(struct fileIdentDesc) +
1200 le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
Marcin Slusarz48d6d8f2008-02-08 04:20:44 -08001201 if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 mark_inode_dirty(old_inode);
Marcin Slusarz4b111112008-02-08 04:20:36 -08001203 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 mark_buffer_dirty_inode(dir_bh, old_inode);
Marcin Slusarz4b111112008-02-08 04:20:36 -08001205
Dave Hansen9a53c3a2006-09-30 23:29:03 -07001206 inode_dec_link_count(old_dir);
Marcin Slusarz4b111112008-02-08 04:20:36 -08001207 if (new_inode)
Dave Hansen9a53c3a2006-09-30 23:29:03 -07001208 inode_dec_link_count(new_inode);
Marcin Slusarz4b111112008-02-08 04:20:36 -08001209 else {
Dave Hansend8c76e62006-09-30 23:29:04 -07001210 inc_nlink(new_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 mark_inode_dirty(new_dir);
1212 }
1213 }
1214
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001215 if (ofi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 if (ofibh.sbh != ofibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -07001217 brelse(ofibh.ebh);
1218 brelse(ofibh.sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 }
1220
1221 retval = 0;
1222
Cyrill Gorcunov28de7942007-07-21 04:37:18 -07001223end_rename:
Jan Kara3bf25cb2007-05-08 00:35:16 -07001224 brelse(dir_bh);
Cyrill Gorcunovcb00ea32007-07-19 01:47:43 -07001225 if (nfi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 if (nfibh.sbh != nfibh.ebh)
Jan Kara3bf25cb2007-05-08 00:35:16 -07001227 brelse(nfibh.ebh);
1228 brelse(nfibh.sbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 }
1230 unlock_kernel();
Cyrill Gorcunov28de7942007-07-21 04:37:18 -07001231
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 return retval;
1233}
1234
Arjan van de Venc5ef1c42007-02-12 00:55:40 -08001235const struct inode_operations udf_dir_inode_operations = {
Cyrill Gorcunov28de7942007-07-21 04:37:18 -07001236 .lookup = udf_lookup,
1237 .create = udf_create,
1238 .link = udf_link,
1239 .unlink = udf_unlink,
1240 .symlink = udf_symlink,
1241 .mkdir = udf_mkdir,
1242 .rmdir = udf_rmdir,
1243 .mknod = udf_mknod,
1244 .rename = udf_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245};