2015-10-04 69 views
3

我將繼續說,這是一個介紹Linux類的家庭作業。如果沒有我自己的廣泛嘗試,我不會發布它,並且由於本學期我是一名遠程學生,所以我無法到校園接受輔導。我需要一些幫助來找出問題所在。在C中使用POSIX中的目錄使用C

實際上,這個任務要求我們編寫一個程序,它的功能與POSIX中的pwd命令具有相同的基本功能,以顯示當前目錄的絕對路徑。我們將與主要一起使用三個功能。我們也不要使用getcwd命令。我將列出他們和他們的目的

  • inum_to_filename:接受三個參數(inode編號來翻譯,在什麼地方的名字被寫入一個緩衝區,緩衝區的大小)。什麼都不返回它是:

    1. 打開當前目錄,
    2. 閱讀的第一個目錄條目,
    3. 如果當前目錄的索引節點相匹配的傳入,名稱複製到緩衝區,並返回。
    4. 否則讀取下一個目錄條目並重覆上一步。
  • filename_to_inum:接受一個參數(代表文件名的char *)。它返回相應的inode號碼。它是:

    1. 從文件inode中讀取信息到內存中的結構中。
    2. 如果有任何問題,請顯示相應的錯誤。
    3. 從結構中返回inode編號。
  • display_path:接受一個參數(來自當前工作目錄的inode)。它什麼都不返回。它是:

    1. 創建一個字符數組以用作目錄名稱的緩衝區。
    2. 使用filename_to_inode獲取父目錄的inode。
    3. 如果父節點inode等於當前的inode,我們已經到達root並且可以返回。
    4. 否則,切換到父目錄並使用inum_to_filename來查找傳入該函數的inode的名稱。使用步驟1中的緩衝區進行存儲。
    5. 遞歸調用display_path來顯示絕對路徑。

下面是代碼:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <dirent.h> 
#include <sys/stat.h> 

void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) { 
    DIR *dir_ptr = opendir("."); 
    struct dirent *dirent_ptr = readdir(dir_ptr); 
    int counter = 0; 

    while (counter != 1) { 
     if (inode_arg == dirent_ptr->d_ino) { 

      strcat(pathBuffer, "/"); 
      strcat(pathBuffer, dirent_ptr->d_name); 

      counter = counter + 1; 
      return; 

     } else { 
      dirent_ptr = readdir(dir_ptr); 
     } 
    } 

    closedir(dir_ptr); 
} 

int filename_to_inum (char *src) { 
    int res = 0; 
    struct stat info; 
    int result = stat(src, &info); 

    if (result != 0) { 
     fprintf(stderr, "Cannot stat "); 
     perror(src); 
     exit(EXIT_FAILURE); 
    } else { 
     res = info.st_ino; 
    } 

    return res; 
} 

void display_path (int ino_src) { 
    int bufSize = 4096; 
    char pathBuffer[bufSize]; 
    int ino_prnt = filename_to_inum(".."); 

    if (ino_src == ino_prnt) { 
     //print for test 
     inum_to_filename(ino_src, pathBuffer, bufSize); 
     printf("%s", pathBuffer); 
     return; 
    } else { 
     //print for test 
     chdir(".."); 
     inum_to_filename(ino_src, pathBuffer, bufSize); 
     display_path(ino_prnt); 
     printf("%s", pathBuffer); 
    } 
} 

int main (int argc, char *argv[]) { 
    int c_ino = filename_to_inum("."); 
    display_path(c_ino); 
    printf("\n"); 
} 

截至目前它顯示「/./MyName」與MYNAME在服務器上我個人命名的目錄。這是我從中運行該程序的目錄。當使用pwd時,我返回「/ home/MyName」。我不確定我的下一步獲得絕對路徑是正確的。

+0

這是一個提示。你正在遞歸調用display_path。每個調用中的pathBuffer變量和每次調用返回後會發生什麼? –

+0

Yuck。我不確定我是否理解在處理中如何使用這些效用函數。如果涉及多個文件系統,我也不相信只有inode數量就足夠了。 'inum_to_filename()'函數大綱並沒有考慮它在當前目錄中不會出現的inode號的可能性。基本技術通常是'查找當前目錄的索引節點號;打開父目錄,讀取條目並查找與當前目錄的inode匹配的inode條目。重複。 –

+0

您需要確保在從inum_to_filename()返回之前關閉打開的目錄,否則會泄漏DIR描述符。 (順便說一下,根目錄的父節點的inode也是根目錄的inode,即'/ .'的inode與'/ ..'相同,通常是inode編號2)。 –

回答

1

的代碼主要是建立在正確的順序每次打印一個名字,所以首要的問題是使用strcat()而不是strcpy()。另外,檢測你在開始時是否在根目錄中很重要;如果你不這樣做,那麼噹噹前目錄是根目錄時,最終可能會得到/.或類似的內容(取決於你如何協調打印)。

這個版本的代碼有:

  • 壓扁循環中inum_to_filename(),而且還增加了錯誤報告。請記住,一個進程可以在一個沒有權限的目錄中運行(它通常需要一個setuid程序 - 雖然可以在程序啓動後更改權限)。在這種情況下,它可能無法打開..(或.)。

  • 失去變量count;它並沒有達到有用的目的。使用分配和測試習慣用法允許代碼包含對readdir()的單個調用。

  • 使用strcpy()而不是strcat()

  • 使用類型ino_t來存儲索引節點編號。尺寸使用size_t

  • 減少filename_to_inum()中的中間變量的數量。

  • 請注意,if (ino_src == ino_prnt)語句正文中的代碼用於根目錄;在沒有測試版的情況下,它什麼都不會做。

  • 請注意,else部分的打印是操作的主要部分,而不僅僅是測試打印。

  • 出錯校驗chdir("..");

  • main()檢測根。

  • 注意到這段代碼並不直接適用於重寫入函數,因爲它在成功時將進程的當前目錄更改爲/

修改後的代碼:

#include <assert.h> 
#include <dirent.h> 
#include <errno.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/stat.h> 
#include <unistd.h> 

static void inum_to_filename(ino_t inode_arg, char *pathBuffer, size_t size_arg) 
{ 
    assert(size_arg > 0); 
    DIR *dir_ptr = opendir("."); 
    if (dir_ptr == 0) 
    { 
     fprintf(stderr, "Failed to open directory '.' (%d: %s)\n", errno, strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 
    struct dirent *dirent_ptr; 

    while ((dirent_ptr = readdir(dir_ptr)) != 0) 
    { 
     if (inode_arg == dirent_ptr->d_ino) 
     { 
      if (strlen(dirent_ptr->d_name) >= size_arg) 
      { 
       fprintf(stderr, "File name %s too long (%zu vs %zu max)\n", 
         dirent_ptr->d_name, strlen(dirent_ptr->d_name), size_arg); 
       exit(EXIT_FAILURE); 
      } 
      strcpy(pathBuffer, dirent_ptr->d_name); 
      break; 
     } 
    } 

    closedir(dir_ptr); 
} 

static ino_t filename_to_inum(char *src) 
{ 
    struct stat info; 

    if (stat(src, &info) != 0) 
    { 
     fprintf(stderr, "Cannot stat "); 
     perror(src); 
     exit(EXIT_FAILURE); 
    } 
    return info.st_ino; 
} 

static void display_path(ino_t ino_src) 
{ 
    size_t bufSize = 4096; 
    char pathBuffer[bufSize]; 
    ino_t ino_prnt = filename_to_inum(".."); 

    if (ino_src == ino_prnt) 
    { 
     // print for test 
     inum_to_filename(ino_src, pathBuffer, bufSize); 
     printf("%s", "(root): /\n"); 
    } 
    else 
    { 
     // print for real 
     if (chdir("..") != 0) 
     { 
      fprintf(stderr, "Failed to chdir to .. (%d: %s)\n", 
        errno, strerror(errno)); 
     } 
     inum_to_filename(ino_src, pathBuffer, bufSize); 
     display_path(ino_prnt); 
     printf("/%s", pathBuffer); 
    } 
} 

int main(void) 
{ 
    ino_t c_ino = filename_to_inum("."); 
    ino_t r_ino = filename_to_inum("/"); 
    if (r_ino == c_ino) 
     putchar('/'); 
    else 
     display_path(c_ino); 
    printf("\n"); 
} 

無疑有其他的方法來解決這個問題。

警告:在/Volumes/CRUZER/Sub-Directory這是一個記憶棒工作時,這給我一些悲傷。它在掃描/Volumes時未能找到inode(1,這是令人驚訝的),我還沒有找出原因。我的一個程序 - 一個getpwd實現 - 工作正常;另一個有不同的問題。我希望我能完成這一切。使用GCC 5.1.0在Mac OS X 10.10.5上進行測試。

1

這真的很不錯:)。 我閱讀並嘗試了您的代碼,它幾乎是正確的。有兩個小問題導致了不正確的行爲。

第一個問題

display_path達到你不需要調用inum_to_filename和打印文件夾的名稱,因爲您已經打印路徑的第一個文件夾中的前一次迭代的根文件夾。這可以防止您的代碼在路徑的開頭顯示「./」。 也就是說,如果條件變爲:

if (ino_src == ino_prnt) { 
     return; 
    } else { 
     chdir(".."); 
     inum_to_filename(ino_src, pathBuffer, bufSize); 
     display_path(ino_prnt); 
     printf("%s", pathBuffer); 
    } 

第二期

你沒有初始化propertly下保存目錄的名稱的緩衝區。這會導致顯示隨機值。要解決此問題,您可以使用memset將緩衝區的初始值設置爲零。

void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) { 
    DIR *dir_ptr = opendir("."); 
    struct dirent *dirent_ptr = readdir(dir_ptr); 
    int counter = 0; 

    memset(pathBuffer, 0, size_arg); 

    while (counter != 1) { 
    ... 
    } 

    closedir(dir_ptr); 
} 

的完整代碼的工作:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <dirent.h> 
#include <sys/stat.h> 

void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) { 
    DIR *dir_ptr = opendir("."); 
    struct dirent *dirent_ptr = readdir(dir_ptr); 
    int counter = 0; 

    memset(pathBuffer, 0, size_arg); 

    while (counter != 1) { 
     if (inode_arg == dirent_ptr->d_ino) { 

      strcat(pathBuffer, "/"); 
      strcat(pathBuffer, dirent_ptr->d_name); 

      counter = counter + 1; 
      return; 

     } else { 
      dirent_ptr = readdir(dir_ptr); 
     } 
    } 

    closedir(dir_ptr); 
} 

int filename_to_inum (char *src) { 
    int res = 0; 
    struct stat info; 
    int result = stat(src, &info); 

    if (result != 0) { 
     fprintf(stderr, "Cannot stat "); 
     perror(src); 
     exit(EXIT_FAILURE); 
    } else { 
     res = info.st_ino; 
    } 

    return res; 
} 

/* 
    - Create an array of characters to use as a buffer for the name of the directory. 
    - Get the inode for the parent directory using filename_to_inode. 
    - If the parent inode is equal to the current inode, we have reached root and can return. 
    - Otherwise, change to the parent directory and use inum_to_filename to find the name for 
    the inode that was passed into the function. Use the buffer from step 1 to store it. 
    - Recursively call display_path to display the absolute path. 
*/ 

void display_path (int ino_src) { 
    int bufSize = 4096; 
    char pathBuffer[bufSize]; 
    int ino_prnt = filename_to_inum(".."); 

    if (ino_src == ino_prnt) { 
     return; 
    } else { 
     chdir(".."); 
     inum_to_filename(ino_src, pathBuffer, bufSize); 
     display_path(ino_prnt); 
     printf("%s", pathBuffer); 
    } 
} 

int main (int argc, char *argv[]) { 
    int c_ino = filename_to_inum("."); 
    display_path(c_ino); 
    printf("\n"); 
} 

輸出:

[email protected]:~/dev$ vi pwd.c 
[email protected]:~/dev$ gcc pwd.c 
[email protected]:~/dev$ ./a.out 
/home/ubuntu/dev 
[email protected]:~/dev$ pwd 
/home/ubuntu/dev 
[email protected]:~/dev$ 
+0

太棒了!但是,在服務器上運行時,它不會高​​於MyName目錄。我想知道爲什麼。不過,這是進步!謝謝! – Monobus

+0

你目前的目錄是什麼?你能過完整路徑嗎?你有沒有在服務器上試過我的完整代碼?這很奇怪,我在我的Linux和MacOSx筆記本電腦上嘗試過,並且都正常工作。 –

+0

你正在使用哪種文件系統? –