~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/smbfs/dir.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  dir.c
  3  *
  4  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  5  *  Copyright (C) 1997 by Volker Lendecke
  6  *
  7  *  Please add a note about your changes to smbfs in the ChangeLog file.
  8  */
  9 
 10 #include <linux/sched.h>
 11 #include <linux/errno.h>
 12 #include <linux/kernel.h>
 13 #include <linux/smp_lock.h>
 14 #include <linux/ctype.h>
 15 
 16 #include <linux/smb_fs.h>
 17 #include <linux/smb_mount.h>
 18 #include <linux/smbno.h>
 19 
 20 #include "smb_debug.h"
 21 
 22 #define SMBFS_MAX_AGE 5*HZ
 23 
 24 static int smb_readdir(struct file *, void *, filldir_t);
 25 static int smb_dir_open(struct inode *, struct file *);
 26 
 27 static struct dentry *smb_lookup(struct inode *, struct dentry *);
 28 static int smb_create(struct inode *, struct dentry *, int);
 29 static int smb_mkdir(struct inode *, struct dentry *, int);
 30 static int smb_rmdir(struct inode *, struct dentry *);
 31 static int smb_unlink(struct inode *, struct dentry *);
 32 static int smb_rename(struct inode *, struct dentry *,
 33                       struct inode *, struct dentry *);
 34 
 35 struct file_operations smb_dir_operations =
 36 {
 37         read:           generic_read_dir,
 38         readdir:        smb_readdir,
 39         ioctl:          smb_ioctl,
 40         open:           smb_dir_open,
 41 };
 42 
 43 struct inode_operations smb_dir_inode_operations =
 44 {
 45         create:         smb_create,
 46         lookup:         smb_lookup,
 47         unlink:         smb_unlink,
 48         mkdir:          smb_mkdir,
 49         rmdir:          smb_rmdir,
 50         rename:         smb_rename,
 51         revalidate:     smb_revalidate_inode,
 52         setattr:        smb_notify_change,
 53 };
 54 
 55 static int 
 56 smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
 57 {
 58         struct dentry *dentry = filp->f_dentry;
 59         struct inode *dir = dentry->d_inode;
 60         struct cache_head *cachep;
 61         int result;
 62 
 63         VERBOSE("reading %s/%s, f_pos=%d\n",
 64                 DENTRY_PATH(dentry),  (int) filp->f_pos);
 65 
 66         result = 0;
 67         switch ((unsigned int) filp->f_pos)
 68         {
 69         case 0:
 70                 if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
 71                         goto out;
 72                 filp->f_pos = 1;
 73         case 1:
 74                 if (filldir(dirent, "..", 2, 1,
 75                                 dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
 76                         goto out;
 77                 filp->f_pos = 2;
 78         }
 79 
 80         /*
 81          * Make sure our inode is up-to-date.
 82          */
 83         result = smb_revalidate_inode(dentry);
 84         if (result)
 85                 goto out;
 86         /*
 87          * Get the cache pointer ...
 88          */
 89         result = -EIO;
 90         cachep = smb_get_dircache(dentry);
 91         if (!cachep)
 92                 goto out;
 93 
 94         /*
 95          * Make sure the cache is up-to-date.
 96          *
 97          * To detect changes on the server we refill on each "new" access.
 98          *
 99          * Directory mtime would be nice to use for finding changes,
100          * unfortunately some servers (NT4) doesn't update on local changes.
101          */
102         if (!cachep->valid || filp->f_pos == 2)
103         {
104                 result = smb_refill_dircache(cachep, dentry);
105                 if (result)
106                         goto out_free;
107         }
108 
109         result = 0;
110 
111         while (1)
112         {
113                 struct cache_dirent this_dirent, *entry = &this_dirent;
114 
115                 if (!smb_find_in_cache(cachep, filp->f_pos, entry))
116                         break;
117                 /*
118                  * Check whether to look up the inode number.
119                  */
120                 if (!entry->ino) {
121                         struct qstr qname;
122                         /* N.B. Make cache_dirent name a qstr! */
123                         qname.name = entry->name;
124                         qname.len  = entry->len;
125                         entry->ino = find_inode_number(dentry, &qname);
126                         if (!entry->ino)
127                                 entry->ino = iunique(dentry->d_sb, 2);
128                 }
129 
130                 if (filldir(dirent, entry->name, entry->len, 
131                                     filp->f_pos, entry->ino, DT_UNKNOWN) < 0)
132                         break;
133                 filp->f_pos += 1;
134         }
135 
136         /*
137          * Release the dircache.
138          */
139 out_free:
140         smb_free_dircache(cachep);
141 out:
142         return result;
143 }
144 
145 /*
146  * Note: in order to allow the smbmount process to open the
147  * mount point, we don't revalidate if conn_pid is NULL.
148  */
149 static int
150 smb_dir_open(struct inode *dir, struct file *file)
151 {
152         struct dentry *dentry = file->f_dentry;
153         struct smb_sb_info *server;
154         int error = 0;
155 
156         VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name,
157                 file->f_dentry->d_name.name);
158 
159         /*
160          * Directory timestamps in the core protocol aren't updated
161          * when a file is added, so we give them a very short TTL.
162          */
163         lock_kernel();
164         server = server_from_dentry(dentry);
165         if (server->opt.protocol < SMB_PROTOCOL_LANMAN2)
166         {
167                 unsigned long age = jiffies - dir->u.smbfs_i.oldmtime;
168                 if (age > 2*HZ)
169                         smb_invalid_dir_cache(dir);
170         }
171 
172         if (server->conn_pid)
173                 error = smb_revalidate_inode(dentry);
174         unlock_kernel();
175         return error;
176 }
177 
178 /*
179  * Dentry operations routines
180  */
181 static int smb_lookup_validate(struct dentry *, int);
182 static int smb_hash_dentry(struct dentry *, struct qstr *);
183 static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
184 static int smb_delete_dentry(struct dentry *);
185 
186 static struct dentry_operations smbfs_dentry_operations =
187 {
188         d_revalidate:   smb_lookup_validate,
189         d_hash:         smb_hash_dentry,
190         d_compare:      smb_compare_dentry,
191         d_delete:       smb_delete_dentry,
192 };
193 
194 static struct dentry_operations smbfs_dentry_operations_case =
195 {
196         d_revalidate:   smb_lookup_validate,
197         d_delete:       smb_delete_dentry,
198 };
199 
200 
201 /*
202  * This is the callback when the dcache has a lookup hit.
203  */
204 static int
205 smb_lookup_validate(struct dentry * dentry, int flags)
206 {
207         struct inode * inode = dentry->d_inode;
208         unsigned long age = jiffies - dentry->d_time;
209         int valid;
210 
211         /*
212          * The default validation is based on dentry age:
213          * we believe in dentries for 5 seconds.  (But each
214          * successful server lookup renews the timestamp.)
215          */
216         valid = (age <= SMBFS_MAX_AGE);
217 #ifdef SMBFS_DEBUG_VERBOSE
218         if (!valid)
219                 VERBOSE("%s/%s not valid, age=%lu\n", 
220                         DENTRY_PATH(dentry), age);
221 #endif
222 
223         if (inode) {
224                 lock_kernel();
225                 if (is_bad_inode(inode)) {
226                         PARANOIA("%s/%s has dud inode\n", DENTRY_PATH(dentry));
227                         valid = 0;
228                 } else if (!valid)
229                         valid = (smb_revalidate_inode(dentry) == 0);
230                 unlock_kernel();
231         } else {
232                 /*
233                  * What should we do for negative dentries?
234                  */
235         }
236         return valid;
237 }
238 
239 static int 
240 smb_hash_dentry(struct dentry *dir, struct qstr *this)
241 {
242         unsigned long hash;
243         int i;
244 
245         hash = init_name_hash();
246         for (i=0; i < this->len ; i++)
247                 hash = partial_name_hash(tolower(this->name[i]), hash);
248         this->hash = end_name_hash(hash);
249   
250         return 0;
251 }
252 
253 static int
254 smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b)
255 {
256         int i, result = 1;
257 
258         if (a->len != b->len)
259                 goto out;
260         for (i=0; i < a->len; i++) {
261                 if (tolower(a->name[i]) != tolower(b->name[i]))
262                         goto out;
263         }
264         result = 0;
265 out:
266         return result;
267 }
268 
269 /*
270  * This is the callback from dput() when d_count is going to 0.
271  * We use this to unhash dentries with bad inodes.
272  */
273 static int
274 smb_delete_dentry(struct dentry * dentry)
275 {
276         if (dentry->d_inode) {
277                 if (is_bad_inode(dentry->d_inode)) {
278                         PARANOIA("bad inode, unhashing %s/%s\n",
279                                  DENTRY_PATH(dentry));
280                         return 1;
281                 }
282         } else {
283                 /* N.B. Unhash negative dentries? */
284         }
285         return 0;
286 }
287 
288 /*
289  * Whenever a lookup succeeds, we know the parent directories
290  * are all valid, so we want to update the dentry timestamps.
291  * N.B. Move this to dcache?
292  */
293 void
294 smb_renew_times(struct dentry * dentry)
295 {
296         for (;;) {
297                 dentry->d_time = jiffies;
298                 if (IS_ROOT(dentry))
299                         break;
300                 dentry = dentry->d_parent;
301         }
302 }
303 
304 static struct dentry *
305 smb_lookup(struct inode *dir, struct dentry *dentry)
306 {
307         struct smb_fattr finfo;
308         struct inode *inode;
309         int error;
310         struct smb_sb_info *server;
311 
312         error = -ENAMETOOLONG;
313         if (dentry->d_name.len > SMB_MAXNAMELEN)
314                 goto out;
315 
316         error = smb_proc_getattr(dentry, &finfo);
317 #ifdef SMBFS_PARANOIA
318         if (error && error != -ENOENT)
319                 PARANOIA("find %s/%s failed, error=%d\n",
320                          DENTRY_PATH(dentry), error);
321 #endif
322 
323         inode = NULL;
324         if (error == -ENOENT)
325                 goto add_entry;
326         if (!error) {
327                 error = -EACCES;
328                 finfo.f_ino = iunique(dentry->d_sb, 2);
329                 inode = smb_iget(dir->i_sb, &finfo);
330                 if (inode) {
331         add_entry:
332                         server = server_from_dentry(dentry);
333                         if (server->mnt->flags & SMB_MOUNT_CASE)
334                                 dentry->d_op = &smbfs_dentry_operations_case;
335                         else
336                                 dentry->d_op = &smbfs_dentry_operations;
337 
338                         d_add(dentry, inode);
339                         smb_renew_times(dentry);
340                         error = 0;
341                 }
342         }
343 out:
344         return ERR_PTR(error);
345 }
346 
347 /*
348  * This code is common to all routines creating a new inode.
349  */
350 static int
351 smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id)
352 {
353         struct smb_sb_info *server = server_from_dentry(dentry);
354         struct inode *inode;
355         int error;
356         struct smb_fattr fattr;
357 
358         VERBOSE("file %s/%s, fileid=%u\n", DENTRY_PATH(dentry), fileid);
359 
360         error = smb_proc_getattr(dentry, &fattr);
361         if (error)
362                 goto out_close;
363 
364         smb_renew_times(dentry);
365         fattr.f_ino = iunique(dentry->d_sb, 2);
366         inode = smb_iget(dentry->d_sb, &fattr);
367         if (!inode)
368                 goto out_no_inode;
369 
370         if (have_id)
371         {
372                 inode->u.smbfs_i.fileid = fileid;
373                 inode->u.smbfs_i.access = SMB_O_RDWR;
374                 inode->u.smbfs_i.open = server->generation;
375         }
376         d_instantiate(dentry, inode);
377 out:
378         return error;
379 
380 out_no_inode:
381         error = -EACCES;
382 out_close:
383         if (have_id)
384         {
385                 PARANOIA("%s/%s failed, error=%d, closing %u\n",
386                          DENTRY_PATH(dentry), error, fileid);
387                 smb_close_fileid(dentry, fileid);
388         }
389         goto out;
390 }
391 
392 /* N.B. How should the mode argument be used? */
393 static int
394 smb_create(struct inode *dir, struct dentry *dentry, int mode)
395 {
396         __u16 fileid;
397         int error;
398 
399         VERBOSE("creating %s/%s, mode=%d\n", DENTRY_PATH(dentry), mode);
400 
401         smb_invalid_dir_cache(dir);
402         error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid);
403         if (!error) {
404                 error = smb_instantiate(dentry, fileid, 1);
405         } else {
406                 PARANOIA("%s/%s failed, error=%d\n",
407                          DENTRY_PATH(dentry), error);
408         }
409         return error;
410 }
411 
412 /* N.B. How should the mode argument be used? */
413 static int
414 smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
415 {
416         int error;
417 
418         smb_invalid_dir_cache(dir);
419         error = smb_proc_mkdir(dentry);
420         if (!error) {
421                 error = smb_instantiate(dentry, 0, 0);
422         }
423         return error;
424 }
425 
426 static int
427 smb_rmdir(struct inode *dir, struct dentry *dentry)
428 {
429         struct inode *inode = dentry->d_inode;
430         int error;
431 
432         /*
433          * Close the directory if it's open.
434          */
435         smb_close(inode);
436 
437         /*
438          * Check that nobody else is using the directory..
439          */
440         error = -EBUSY;
441         if (!d_unhashed(dentry))
442                 goto out;
443 
444         error = smb_proc_rmdir(dentry);
445 
446 out:
447         return error;
448 }
449 
450 static int
451 smb_unlink(struct inode *dir, struct dentry *dentry)
452 {
453         int error;
454 
455         /*
456          * Close the file if it's open.
457          */
458         smb_close(dentry->d_inode);
459 
460         error = smb_proc_unlink(dentry);
461         if (!error)
462                 smb_renew_times(dentry);
463         return error;
464 }
465 
466 static int
467 smb_rename(struct inode *old_dir, struct dentry *old_dentry,
468            struct inode *new_dir, struct dentry *new_dentry)
469 {
470         int error;
471 
472         /*
473          * Close any open files, and check whether to delete the
474          * target before attempting the rename.
475          */
476         if (old_dentry->d_inode)
477                 smb_close(old_dentry->d_inode);
478         if (new_dentry->d_inode)
479         {
480                 smb_close(new_dentry->d_inode);
481                 error = smb_proc_unlink(new_dentry);
482                 if (error)
483                 {
484                         VERBOSE("unlink %s/%s, error=%d\n",
485                                 DENTRY_PATH(new_dentry), error);
486                         goto out;
487                 }
488                 /* FIXME */
489                 d_delete(new_dentry);
490         }
491 
492         smb_invalid_dir_cache(old_dir);
493         smb_invalid_dir_cache(new_dir);
494         error = smb_proc_mv(old_dentry, new_dentry);
495         if (!error)
496         {
497                 smb_renew_times(old_dentry);
498                 smb_renew_times(new_dentry);
499         }
500 out:
501         return error;
502 }
503 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.