1*10465441SEvalZero /*
2*10465441SEvalZero * JFFS2 -- Journalling Flash File System, Version 2.
3*10465441SEvalZero *
4*10465441SEvalZero * Copyright (C) 2001-2003 Free Software Foundation, Inc.
5*10465441SEvalZero *
6*10465441SEvalZero * Created by David Woodhouse <[email protected]>
7*10465441SEvalZero *
8*10465441SEvalZero * For licensing information, see the file 'LICENCE' in this directory.
9*10465441SEvalZero *
10*10465441SEvalZero * $Id: dir-ecos.c,v 1.11 2005/02/08 19:36:27 lunn Exp $
11*10465441SEvalZero *
12*10465441SEvalZero */
13*10465441SEvalZero
14*10465441SEvalZero #include <linux/kernel.h>
15*10465441SEvalZero #include <linux/crc32.h>
16*10465441SEvalZero #include "nodelist.h"
17*10465441SEvalZero
18*10465441SEvalZero /***********************************************************************/
19*10465441SEvalZero
20*10465441SEvalZero /* Takes length argument because it can be either NUL-terminated or '/'-terminated */
jffs2_lookup(struct _inode * dir_i,const unsigned char * d_name,int namelen)21*10465441SEvalZero struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *d_name, int namelen)
22*10465441SEvalZero {
23*10465441SEvalZero struct jffs2_inode_info *dir_f;
24*10465441SEvalZero struct jffs2_full_dirent *fd = NULL, *fd_list;
25*10465441SEvalZero uint32_t ino = 0;
26*10465441SEvalZero uint32_t hash = full_name_hash(d_name, namelen);
27*10465441SEvalZero struct _inode *inode = NULL;
28*10465441SEvalZero
29*10465441SEvalZero D1(printk("jffs2_lookup()\n"));
30*10465441SEvalZero
31*10465441SEvalZero dir_f = JFFS2_INODE_INFO(dir_i);
32*10465441SEvalZero
33*10465441SEvalZero down(&dir_f->sem);
34*10465441SEvalZero
35*10465441SEvalZero /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
36*10465441SEvalZero for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= hash; fd_list = fd_list->next) {
37*10465441SEvalZero if (fd_list->nhash == hash &&
38*10465441SEvalZero (!fd || fd_list->version > fd->version) &&
39*10465441SEvalZero strlen((char *)fd_list->name) == namelen &&
40*10465441SEvalZero !strncmp((char *)fd_list->name, (char *)d_name, namelen)) {
41*10465441SEvalZero fd = fd_list;
42*10465441SEvalZero }
43*10465441SEvalZero }
44*10465441SEvalZero if (fd)
45*10465441SEvalZero ino = fd->ino;
46*10465441SEvalZero up(&dir_f->sem);
47*10465441SEvalZero if (ino) {
48*10465441SEvalZero inode = jffs2_iget(dir_i->i_sb, ino);
49*10465441SEvalZero if (IS_ERR(inode)) {
50*10465441SEvalZero printk("jffs2_iget() failed for ino #%u\n", ino);
51*10465441SEvalZero return inode;
52*10465441SEvalZero }
53*10465441SEvalZero }
54*10465441SEvalZero
55*10465441SEvalZero return inode;
56*10465441SEvalZero }
57*10465441SEvalZero
58*10465441SEvalZero /***********************************************************************/
59*10465441SEvalZero
60*10465441SEvalZero
61*10465441SEvalZero
jffs2_create(struct _inode * dir_i,const unsigned char * d_name,int mode,struct _inode ** new_i)62*10465441SEvalZero int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode,
63*10465441SEvalZero struct _inode **new_i)
64*10465441SEvalZero {
65*10465441SEvalZero struct jffs2_raw_inode *ri;
66*10465441SEvalZero struct jffs2_inode_info *f, *dir_f;
67*10465441SEvalZero struct jffs2_sb_info *c;
68*10465441SEvalZero struct _inode *inode;
69*10465441SEvalZero int ret;
70*10465441SEvalZero
71*10465441SEvalZero ri = jffs2_alloc_raw_inode();
72*10465441SEvalZero if (!ri)
73*10465441SEvalZero return -ENOMEM;
74*10465441SEvalZero
75*10465441SEvalZero c = JFFS2_SB_INFO(dir_i->i_sb);
76*10465441SEvalZero
77*10465441SEvalZero D1(printk(KERN_DEBUG "jffs2_create()\n"));
78*10465441SEvalZero
79*10465441SEvalZero inode = jffs2_new_inode(dir_i, mode, ri);
80*10465441SEvalZero
81*10465441SEvalZero if (IS_ERR(inode)) {
82*10465441SEvalZero D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n"));
83*10465441SEvalZero jffs2_free_raw_inode(ri);
84*10465441SEvalZero return PTR_ERR(inode);
85*10465441SEvalZero }
86*10465441SEvalZero
87*10465441SEvalZero f = JFFS2_INODE_INFO(inode);
88*10465441SEvalZero dir_f = JFFS2_INODE_INFO(dir_i);
89*10465441SEvalZero
90*10465441SEvalZero ret = jffs2_do_create(c, dir_f, f, ri,
91*10465441SEvalZero (const char *)d_name,
92*10465441SEvalZero strlen((char *)d_name));
93*10465441SEvalZero
94*10465441SEvalZero if (ret) {
95*10465441SEvalZero inode->i_nlink = 0;
96*10465441SEvalZero jffs2_iput(inode);
97*10465441SEvalZero jffs2_free_raw_inode(ri);
98*10465441SEvalZero return ret;
99*10465441SEvalZero }
100*10465441SEvalZero
101*10465441SEvalZero jffs2_free_raw_inode(ri);
102*10465441SEvalZero
103*10465441SEvalZero D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d)\n",
104*10465441SEvalZero inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink));
105*10465441SEvalZero *new_i = inode;
106*10465441SEvalZero return 0;
107*10465441SEvalZero }
108*10465441SEvalZero
109*10465441SEvalZero /***********************************************************************/
110*10465441SEvalZero
111*10465441SEvalZero
jffs2_unlink(struct _inode * dir_i,struct _inode * d_inode,const unsigned char * d_name)112*10465441SEvalZero int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name)
113*10465441SEvalZero {
114*10465441SEvalZero struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
115*10465441SEvalZero struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
116*10465441SEvalZero struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode);
117*10465441SEvalZero int ret;
118*10465441SEvalZero
119*10465441SEvalZero ret = jffs2_do_unlink(c, dir_f, (const char *)d_name,
120*10465441SEvalZero strlen((char *)d_name), dead_f);
121*10465441SEvalZero if (dead_f->inocache)
122*10465441SEvalZero d_inode->i_nlink = dead_f->inocache->nlink;
123*10465441SEvalZero return ret;
124*10465441SEvalZero }
125*10465441SEvalZero /***********************************************************************/
126*10465441SEvalZero
127*10465441SEvalZero
jffs2_link(struct _inode * old_d_inode,struct _inode * dir_i,const unsigned char * d_name)128*10465441SEvalZero int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name)
129*10465441SEvalZero {
130*10465441SEvalZero struct jffs2_sb_info *c = JFFS2_SB_INFO(old_d_inode->i_sb);
131*10465441SEvalZero struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_d_inode);
132*10465441SEvalZero struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
133*10465441SEvalZero int ret;
134*10465441SEvalZero
135*10465441SEvalZero /* XXX: This is ugly */
136*10465441SEvalZero uint8_t type = (old_d_inode->i_mode & S_IFMT) >> 12;
137*10465441SEvalZero if (!type) type = DT_REG;
138*10465441SEvalZero
139*10465441SEvalZero ret = jffs2_do_link(c, dir_f, f->inocache->ino, type,
140*10465441SEvalZero (const char * )d_name,
141*10465441SEvalZero strlen((char *)d_name));
142*10465441SEvalZero
143*10465441SEvalZero if (!ret) {
144*10465441SEvalZero down(&f->sem);
145*10465441SEvalZero old_d_inode->i_nlink = ++f->inocache->nlink;
146*10465441SEvalZero up(&f->sem);
147*10465441SEvalZero }
148*10465441SEvalZero return ret;
149*10465441SEvalZero }
150*10465441SEvalZero
jffs2_mkdir(struct _inode * dir_i,const unsigned char * d_name,int mode)151*10465441SEvalZero int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode)
152*10465441SEvalZero {
153*10465441SEvalZero struct jffs2_inode_info *f, *dir_f;
154*10465441SEvalZero struct jffs2_sb_info *c;
155*10465441SEvalZero struct _inode *inode;
156*10465441SEvalZero struct jffs2_raw_inode *ri;
157*10465441SEvalZero struct jffs2_raw_dirent *rd;
158*10465441SEvalZero struct jffs2_full_dnode *fn;
159*10465441SEvalZero struct jffs2_full_dirent *fd;
160*10465441SEvalZero int namelen;
161*10465441SEvalZero uint32_t alloclen, phys_ofs;
162*10465441SEvalZero int ret;
163*10465441SEvalZero
164*10465441SEvalZero mode |= S_IFDIR;
165*10465441SEvalZero
166*10465441SEvalZero ri = jffs2_alloc_raw_inode();
167*10465441SEvalZero if (!ri)
168*10465441SEvalZero return -ENOMEM;
169*10465441SEvalZero
170*10465441SEvalZero c = JFFS2_SB_INFO(dir_i->i_sb);
171*10465441SEvalZero
172*10465441SEvalZero /* Try to reserve enough space for both node and dirent.
173*10465441SEvalZero * Just the node will do for now, though
174*10465441SEvalZero */
175*10465441SEvalZero namelen = strlen((char *)d_name);
176*10465441SEvalZero ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
177*10465441SEvalZero
178*10465441SEvalZero if (ret) {
179*10465441SEvalZero jffs2_free_raw_inode(ri);
180*10465441SEvalZero return ret;
181*10465441SEvalZero }
182*10465441SEvalZero
183*10465441SEvalZero inode = jffs2_new_inode(dir_i, mode, ri);
184*10465441SEvalZero
185*10465441SEvalZero if (IS_ERR(inode)) {
186*10465441SEvalZero jffs2_free_raw_inode(ri);
187*10465441SEvalZero jffs2_complete_reservation(c);
188*10465441SEvalZero return PTR_ERR(inode);
189*10465441SEvalZero }
190*10465441SEvalZero
191*10465441SEvalZero f = JFFS2_INODE_INFO(inode);
192*10465441SEvalZero
193*10465441SEvalZero ri->data_crc = cpu_to_je32(0);
194*10465441SEvalZero ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
195*10465441SEvalZero
196*10465441SEvalZero fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
197*10465441SEvalZero
198*10465441SEvalZero jffs2_free_raw_inode(ri);
199*10465441SEvalZero
200*10465441SEvalZero if (IS_ERR(fn)) {
201*10465441SEvalZero /* Eeek. Wave bye bye */
202*10465441SEvalZero up(&f->sem);
203*10465441SEvalZero jffs2_complete_reservation(c);
204*10465441SEvalZero inode->i_nlink = 0;
205*10465441SEvalZero jffs2_iput(inode);
206*10465441SEvalZero return PTR_ERR(fn);
207*10465441SEvalZero }
208*10465441SEvalZero /* No data here. Only a metadata node, which will be
209*10465441SEvalZero obsoleted by the first data write
210*10465441SEvalZero */
211*10465441SEvalZero f->metadata = fn;
212*10465441SEvalZero up(&f->sem);
213*10465441SEvalZero
214*10465441SEvalZero jffs2_complete_reservation(c);
215*10465441SEvalZero ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
216*10465441SEvalZero if (ret) {
217*10465441SEvalZero /* Eep. */
218*10465441SEvalZero inode->i_nlink = 0;
219*10465441SEvalZero jffs2_iput(inode);
220*10465441SEvalZero return ret;
221*10465441SEvalZero }
222*10465441SEvalZero
223*10465441SEvalZero rd = jffs2_alloc_raw_dirent();
224*10465441SEvalZero if (!rd) {
225*10465441SEvalZero /* Argh. Now we treat it like a normal delete */
226*10465441SEvalZero jffs2_complete_reservation(c);
227*10465441SEvalZero inode->i_nlink = 0;
228*10465441SEvalZero jffs2_iput(inode);
229*10465441SEvalZero return -ENOMEM;
230*10465441SEvalZero }
231*10465441SEvalZero
232*10465441SEvalZero dir_f = JFFS2_INODE_INFO(dir_i);
233*10465441SEvalZero down(&dir_f->sem);
234*10465441SEvalZero
235*10465441SEvalZero rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
236*10465441SEvalZero rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
237*10465441SEvalZero rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
238*10465441SEvalZero rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
239*10465441SEvalZero
240*10465441SEvalZero rd->pino = cpu_to_je32(dir_i->i_ino);
241*10465441SEvalZero rd->version = cpu_to_je32(++dir_f->highest_version);
242*10465441SEvalZero rd->ino = cpu_to_je32(inode->i_ino);
243*10465441SEvalZero rd->mctime = cpu_to_je32(jffs2_get_timestamp());
244*10465441SEvalZero rd->nsize = namelen;
245*10465441SEvalZero rd->type = DT_DIR;
246*10465441SEvalZero rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
247*10465441SEvalZero rd->name_crc = cpu_to_je32(crc32(0, d_name, namelen));
248*10465441SEvalZero
249*10465441SEvalZero fd = jffs2_write_dirent(c, dir_f, rd, d_name, namelen, phys_ofs, ALLOC_NORMAL);
250*10465441SEvalZero
251*10465441SEvalZero jffs2_complete_reservation(c);
252*10465441SEvalZero jffs2_free_raw_dirent(rd);
253*10465441SEvalZero
254*10465441SEvalZero if (IS_ERR(fd)) {
255*10465441SEvalZero /* dirent failed to write. Delete the inode normally
256*10465441SEvalZero as if it were the final unlink() */
257*10465441SEvalZero up(&dir_f->sem);
258*10465441SEvalZero inode->i_nlink = 0;
259*10465441SEvalZero jffs2_iput(inode);
260*10465441SEvalZero return PTR_ERR(fd);
261*10465441SEvalZero }
262*10465441SEvalZero
263*10465441SEvalZero /* Link the fd into the inode's list, obsoleting an old
264*10465441SEvalZero one if necessary. */
265*10465441SEvalZero jffs2_add_fd_to_list(c, fd, &dir_f->dents);
266*10465441SEvalZero up(&dir_f->sem);
267*10465441SEvalZero
268*10465441SEvalZero jffs2_iput(inode);
269*10465441SEvalZero return 0;
270*10465441SEvalZero }
271*10465441SEvalZero
jffs2_rmdir(struct _inode * dir_i,struct _inode * d_inode,const unsigned char * d_name)272*10465441SEvalZero int jffs2_rmdir (struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name)
273*10465441SEvalZero {
274*10465441SEvalZero struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode);
275*10465441SEvalZero struct jffs2_full_dirent *fd;
276*10465441SEvalZero
277*10465441SEvalZero for (fd = f->dents ; fd; fd = fd->next) {
278*10465441SEvalZero if (fd->ino)
279*10465441SEvalZero return EPERM; //-ENOTEMPTY;
280*10465441SEvalZero }
281*10465441SEvalZero return jffs2_unlink(dir_i, d_inode, d_name);
282*10465441SEvalZero }
283*10465441SEvalZero
jffs2_rename(struct _inode * old_dir_i,struct _inode * d_inode,const unsigned char * old_d_name,struct _inode * new_dir_i,const unsigned char * new_d_name)284*10465441SEvalZero int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsigned char *old_d_name,
285*10465441SEvalZero struct _inode *new_dir_i, const unsigned char *new_d_name)
286*10465441SEvalZero {
287*10465441SEvalZero int ret;
288*10465441SEvalZero struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
289*10465441SEvalZero struct jffs2_inode_info *victim_f = NULL;
290*10465441SEvalZero uint8_t type;
291*10465441SEvalZero
292*10465441SEvalZero #if 0 /* FIXME -- this really doesn't belong in individual file systems.
293*10465441SEvalZero The fileio code ought to do this for us, or at least part of it */
294*10465441SEvalZero if (new_dentry->d_inode) {
295*10465441SEvalZero if (S_ISDIR(d_inode->i_mode) &&
296*10465441SEvalZero !S_ISDIR(new_dentry->d_inode->i_mode)) {
297*10465441SEvalZero /* Cannot rename directory over non-directory */
298*10465441SEvalZero return -EINVAL;
299*10465441SEvalZero }
300*10465441SEvalZero
301*10465441SEvalZero victim_f = JFFS2_INODE_INFO(new_dentry->d_inode);
302*10465441SEvalZero
303*10465441SEvalZero if (S_ISDIR(new_dentry->d_inode->i_mode)) {
304*10465441SEvalZero struct jffs2_full_dirent *fd;
305*10465441SEvalZero
306*10465441SEvalZero if (!S_ISDIR(d_inode->i_mode)) {
307*10465441SEvalZero /* Cannot rename non-directory over directory */
308*10465441SEvalZero return -EINVAL;
309*10465441SEvalZero }
310*10465441SEvalZero down(&victim_f->sem);
311*10465441SEvalZero for (fd = victim_f->dents; fd; fd = fd->next) {
312*10465441SEvalZero if (fd->ino) {
313*10465441SEvalZero up(&victim_f->sem);
314*10465441SEvalZero return -ENOTEMPTY;
315*10465441SEvalZero }
316*10465441SEvalZero }
317*10465441SEvalZero up(&victim_f->sem);
318*10465441SEvalZero }
319*10465441SEvalZero }
320*10465441SEvalZero #endif
321*10465441SEvalZero
322*10465441SEvalZero /* XXX: We probably ought to alloc enough space for
323*10465441SEvalZero both nodes at the same time. Writing the new link,
324*10465441SEvalZero then getting -ENOSPC, is quite bad :)
325*10465441SEvalZero */
326*10465441SEvalZero
327*10465441SEvalZero /* Make a hard link */
328*10465441SEvalZero
329*10465441SEvalZero /* XXX: This is ugly */
330*10465441SEvalZero type = (d_inode->i_mode & S_IFMT) >> 12;
331*10465441SEvalZero if (!type) type = DT_REG;
332*10465441SEvalZero
333*10465441SEvalZero ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
334*10465441SEvalZero d_inode->i_ino, type,
335*10465441SEvalZero (const char *)new_d_name,
336*10465441SEvalZero strlen((char *)new_d_name));
337*10465441SEvalZero
338*10465441SEvalZero if (ret)
339*10465441SEvalZero return ret;
340*10465441SEvalZero
341*10465441SEvalZero if (victim_f) {
342*10465441SEvalZero /* There was a victim. Kill it off nicely */
343*10465441SEvalZero /* Don't oops if the victim was a dirent pointing to an
344*10465441SEvalZero inode which didn't exist. */
345*10465441SEvalZero if (victim_f->inocache) {
346*10465441SEvalZero down(&victim_f->sem);
347*10465441SEvalZero victim_f->inocache->nlink--;
348*10465441SEvalZero up(&victim_f->sem);
349*10465441SEvalZero }
350*10465441SEvalZero }
351*10465441SEvalZero
352*10465441SEvalZero /* Unlink the original */
353*10465441SEvalZero ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
354*10465441SEvalZero (const char *)old_d_name,
355*10465441SEvalZero strlen((char *)old_d_name), NULL);
356*10465441SEvalZero
357*10465441SEvalZero if (ret) {
358*10465441SEvalZero /* Oh shit. We really ought to make a single node which can do both atomically */
359*10465441SEvalZero struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode);
360*10465441SEvalZero down(&f->sem);
361*10465441SEvalZero if (f->inocache)
362*10465441SEvalZero d_inode->i_nlink = f->inocache->nlink++;
363*10465441SEvalZero up(&f->sem);
364*10465441SEvalZero
365*10465441SEvalZero printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
366*10465441SEvalZero }
367*10465441SEvalZero return ret;
368*10465441SEvalZero }
369*10465441SEvalZero
370