In article <82b9qt$8uv$[EMAIL PROTECTED]> you wrote:
> I am trying to find a way to get the full pathname from a dentry
> refering a file. I tried d_path, and in one occasion I got
> nothing, and in the other I got rubbish, then the path
> I was expecting, and then (deleted).

I implemented that. Any comment ?  It seems to work in my application
(albeit I couldn't test locking and parallelism issues).

/* NAME
 *    dentry_get_path
 * DESCRIPTION
 *    Writes the complete NUL terminated path, including /,
 *    to the given buffer, in the usual order. The function
 *    doesn't sleep. The buffer is a kernel-space buffer,
 *    which can be accessed directly.
 * RESULT
 *    0        operation succeeded.
 *    -ENOMEM  buffer was too small, buffer can't be considered.
 *    -EIO     integrity failure when evaluating path, buffer can't be
 *             considered.
 * NOTES
 *    - We do not lock the dentries since we assume we will not
 *      sleep at all. This is maybe wrong in SMP.
 *    - We remove all the leading /.
 * BUGS
 * TODO
 */
static int dentry_get_path(mfs_dentry_t *dentry,
                           char *buffer,
                           int buffer_length);

static int dentry_get_path(mfs_dentry_t *dentry,
                           char *buffer,
                           int buffer_length) {
   char *after_buffer_address = buffer + buffer_length; /* is OUTSIDE ! */
   char *last_address = after_buffer_address;

   while (dentry) {
      int element_size = dentry->d_name.len + 1;

      /* The +1 either accounts for the preceeding / or the last NUL */

      if (element_size == 1) {
         return -EIO;
      }
      else if (element_size > buffer_length) {
         return -ENOMEM;
      }
      else {
         after_buffer_address -= element_size;
         /* Thus, we now reserved from current..last_current */
         buffer_length -= element_size;
         memcpy(after_buffer_address + 1,
                dentry->d_name.name,
                dentry->d_name.len);
         *after_buffer_address = '/';
         printk("[%s] %d\n", dentry->d_name.name, dentry->d_name.len);
      }

      if (dentry == dentry->d_parent) {
         dentry = NULL;
      }
      else {
         dentry = dentry->d_parent;
      }
   }

   /* Now shift the buffer, ignoring all the first / */

   while ((after_buffer_address < last_address)
          && (*after_buffer_address == '/')) {
      after_buffer_address++;
   }

   /* We could have used memcpy if we were sure it was supporting
    * overlapped copies.
    */
   while (after_buffer_address < last_address) {
      *buffer = *after_buffer_address;
      buffer++;
      after_buffer_address++;
   }

   *buffer = '\0'; /* and finish the buffer. There is room because of the
                    * initial removed /.
                    */

   return 0;   
}

Reply via email to