質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

1回答

5377閲覧

cp -r コマンドのC言語による実装

thoifon

総合スコア12

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2016/07/01 17:34

###前提・実現したいこと
ls -r コマンドのC言語のソースコードを参考にして
cp -r コマンドを実装しているのですが
どこを変えていいのかわかりません…

###該当のソースコード

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <unistd.h> 5#include <dirent.h> 6#include <sys/types.h> 7#include <sys/stat.h> 8#include <errno.h> 9 10struct strbuf { 11 char *ptr; 12 size_t len; 13}; 14 15void traverse(struct strbuf *buf); 16void traverseSub(struct strbuf *buf, int first); 17struct strbuf *strbuf_new(void); 18void strbuf_realloc(struct strbuf *buf, size_t size); 19 20void print_error(char *s){ 21 fprintf(stderr, "%s: %s\n", s, strerror(errno)); 22} 23 24void die (const char *s){ 25 perror(s); 26 exit(1); 27} 28int main(int argc, char *argv[]){ 29 struct strbuf *pathbuf; 30 31 if(argc != 2){ 32 fprintf(stderr, "Usage: %s dir\n", argv[0]); 33 exit(1); 34 } 35 pathbuf = strbuf_new(); 36 strbuf_realloc(pathbuf, strlen(argv[1])); 37 strcpy(pathbuf->ptr, argv[1]); 38 traverse(pathbuf); 39 exit(0); 40} 41 42void traverse(struct strbuf *pathbuf){ 43 traverseSub(pathbuf, 1); 44} 45 46void traverseSub(struct strbuf *pathbuf, int first){ 47 DIR *d; 48 struct dirent *ent; 49 struct stat st; 50 51 d = opendir(pathbuf->ptr); 52 if (!d) { 53 switch (errno){ 54 case ENOTDIR: 55 return; 56 case ENOENT: 57 if(first){ 58 die(pathbuf->ptr); 59 } else { 60 return; 61 } 62 case EACCES: 63 puts(pathbuf->ptr); 64 print_error(pathbuf->ptr); 65 return; 66 default: 67 perror(pathbuf->ptr); 68 exit(1); 69 } 70 } 71 puts(pathbuf->ptr); 72 while(ent = readdir(d)){ 73 if(strcmp(ent->d_name, ".") == 0) 74 continue; 75 if(strcmp(ent->d_name, "..") == 0) 76 continue; 77 strbuf_realloc(pathbuf, pathbuf->len + 1 + strlen(ent->d_name) + 1); 78 // special handling for the root directory 79 if(strcmp(pathbuf->ptr, "/") != 0){ 80 strcat(pathbuf->ptr, "/"); 81 } 82 strcat(pathbuf->ptr, ent->d_name); 83 if(lstat(pathbuf->ptr, &st) < 0){ 84 switch (errno){ 85 case ENOENT: 86 break; 87 case EACCES: 88 print_error(pathbuf->ptr); 89 break; 90 default: 91 die(pathbuf->ptr); 92 } 93 } else { 94 if (S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode)) { 95 traverseSub(pathbuf, 0); 96 } else { 97 puts(pathbuf->ptr); 98 } 99 } 100 *strrchr(pathbuf->ptr, '/') = '\0'; 101 } 102 closedir(d); 103 } 104 105#define INITLEN 1024 106 107struct strbuf * strbuf_new(void){ 108 struct strbuf *buf; 109 110 buf = (struct strbuf*)malloc(sizeof(struct strbuf)); 111 if (!buf) { 112 die("malloc(3)"); 113 } 114 buf->ptr = malloc(INITLEN); 115 if(!buf->ptr){ 116 die("malloc(3)"); 117 } 118 buf->len = INITLEN; 119 return buf; 120} 121 122void strbuf_realloc(struct strbuf *buf, size_t len){ 123 char *tmp; 124 125 if(buf->len > len) 126 return; 127 tmp = realloc(buf->ptr, len); 128 if (!tmp) { 129 die("realloc(3)"); 130 } 131 buf->ptr = tmp; 132 buf->len = len; 133}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/08/14 15:17

ソースコード中にコメントや、質問者ご自身の解釈を付記すれば、課題が浮かび上がると思います。
guest

回答1

0

ベストアンサー

既にお答えは必要ないかもしれませんが、と在る人のやり方です。

・ソースコードは ls -r を実行されると言う事で多分、ディレクトリ内をリカーシブルにリストするものと考えます。なのでディレクトリとファイル名が出力されます。
・目的のcp -rは、Linuxでの cp -R dir1 dir2と同様な動きをする事と考えます。(ディレクトリのコピー)
・だとすると、どこを変更するかと考えて、まずは全体の動きを見たいので、各サブルーチンにDEBUG文をprintfを最初と最後に入れます。
・実行結果からおおその動きが分かりますので、さらにファイルをcpする際に必要そうな値の場所にもprintf文を入れます。
・cpに必要な情報が揃ったところで、次にdirとfileかを判断してる箇所に、ディレクトリ作成、ファイルのコピーを行うサブルーチンを加えます。(mkdirやcpはソースを持って来てサブルーチン化します。)

プログラムを修正する場合、こんな感じでやっております。

サンプルですのでご参考としてください。

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> struct strbuf { char *ptr; size_t len; }; void traverse(struct strbuf *buf); void traverseSub(struct strbuf *buf, int first); struct strbuf *strbuf_new(void); void strbuf_realloc(struct strbuf *buf, size_t size); void print_error(char *s){ fprintf(stderr, "%s: %s\n", s, strerror(errno)); } void die (const char *s){ perror(s); exit(1); } char dir1[256]; char dir2[256]; int ccp(char *frfile,char *tofile) { FILE* fpSrc; FILE* fpDest; char c; fpSrc = fopen( frfile, "rb" ); if( fpSrc == NULL ){ exit( EXIT_FAILURE ); } fpDest = fopen( tofile, "wb" ); if( fpDest == NULL ){ exit( EXIT_FAILURE ); } while( 1 ){ /* バイナリデータとして 1Byteずつ読み込み、1Byteずつ書き込む */ fread( &c, sizeof(c), 1, fpSrc ); if( feof( fpSrc ) ){ break; } if( ferror( fpSrc ) ){ exit( EXIT_FAILURE ); } fwrite( &c, sizeof(c), 1, fpDest ); } if( fclose( fpDest ) == EOF ){ fputs( "ファイルクローズに失敗しました。\n", stderr ); exit( EXIT_FAILURE ); } if( fclose( fpSrc ) == EOF ){ fputs( "ファイルクローズに失敗しました。\n", stderr ); exit( EXIT_FAILURE ); } return 0; } int main(int argc, char *argv[]){ struct strbuf *pathbuf; if(argc != 3){ fprintf(stderr, "Usage:cpdir dir1 dir2\n"); exit(1); } pathbuf = strbuf_new(); strbuf_realloc(pathbuf, strlen(argv[1])); strcpy(pathbuf->ptr, argv[1]); strcpy(dir1, argv[1]); strcpy(dir2, argv[2]); traverse(pathbuf); exit(0); } void traverse(struct strbuf *pathbuf){ traverseSub(pathbuf, 1); } void traverseSub(struct strbuf *pathbuf, int first){ DIR *d; struct dirent *ent; struct stat st; char to_name[2048]; // printf("traverseSub S\n"); if (first){ strcpy(to_name,dir2); }else{ strcpy(to_name,dir2); strcpy(to_name+strlen(dir2),pathbuf->ptr+strlen(dir1)); } d = opendir(pathbuf->ptr); if (!d) { switch (errno){ case ENOTDIR: return; case ENOENT: if(first){ die(pathbuf->ptr); } else { return; } case EACCES: puts(pathbuf->ptr); print_error(pathbuf->ptr); return; default: perror(pathbuf->ptr); exit(1); } } //printf("Dir:%s \n", pathbuf->ptr); //printf("Dir2:%s \n", to_name); puts(pathbuf->ptr); if (mkdir(to_name,0755) == 0){ printf("%s mkdir\n", to_name); } while(ent = readdir(d)){ if(strcmp(ent->d_name, ".") == 0) continue; if(strcmp(ent->d_name, "..") == 0) continue; strbuf_realloc(pathbuf, pathbuf->len + 1 + strlen(ent->d_name) + 1); // special handling for the root directory if(strcmp(pathbuf->ptr, "/") != 0){ strcat(pathbuf->ptr, "/"); } strcat(pathbuf->ptr, ent->d_name); if(lstat(pathbuf->ptr, &st) < 0){ switch (errno){ case ENOENT: break; case EACCES: print_error(pathbuf->ptr); break; default: die(pathbuf->ptr); } } else { if (S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode)) { traverseSub(pathbuf, 0); } else { puts(pathbuf->ptr); strcpy(to_name,dir2); strcpy(to_name+strlen(dir2),pathbuf->ptr+strlen(dir1)); if (ccp(pathbuf->ptr, to_name)){ printf("File:%s\n",to_name); } } } *strrchr(pathbuf->ptr, '/') = '\0'; } closedir(d); //printf("traverseSub E\n"); } #define INITLEN 1024 struct strbuf * strbuf_new(void){ struct strbuf *buf; buf = (struct strbuf*)malloc(sizeof(struct strbuf)); if (!buf) { die("malloc(3)"); } buf->ptr = malloc(INITLEN); if(!buf->ptr){ die("malloc(3)"); } buf->len = INITLEN; return buf; } void strbuf_realloc(struct strbuf *buf, size_t len){ char *tmp; if(buf->len > len) return; tmp = realloc(buf->ptr, len); if (!tmp) { die("realloc(3)"); } buf->ptr = tmp; buf->len = len; }

投稿2016/08/28 23:24

編集2016/08/29 02:35
A.Ichi

総合スコア4070

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問