random: Fix behavior of kernel option "-rs".
[pintos-anon] / src / tests / filesys / extended / tar.c
1 /* tar.c
2
3    Creates a tar archive. */
4
5 #include <ustar.h>
6 #include <syscall.h>
7 #include <stdio.h>
8 #include <string.h>
9
10 static void usage (void);
11 static bool make_tar_archive (const char *archive_name,
12                               char *files[], size_t file_cnt);
13
14 int
15 main (int argc, char *argv[]) 
16 {
17   if (argc < 3)
18     usage ();
19
20   return (make_tar_archive (argv[1], argv + 2, argc - 2)
21           ? EXIT_SUCCESS : EXIT_FAILURE);
22 }
23
24 static void
25 usage (void) 
26 {
27   printf ("tar, tar archive creator\n"
28           "Usage: tar ARCHIVE FILE...\n"
29           "where ARCHIVE is the tar archive to create\n"
30           "  and FILE... is a list of files or directories to put into it.\n"
31           "(ARCHIVE itself will not be included in the archive, even if it\n"
32           "is in a directory to be archived.)\n");
33   exit (EXIT_FAILURE);
34 }
35 \f
36 static bool archive_file (char file_name[], size_t file_name_size,
37                           int archive_fd, bool *write_error);
38
39 static bool archive_ordinary_file (const char *file_name, int file_fd,
40                                    int archive_fd, bool *write_error);
41 static bool archive_directory (char file_name[], size_t file_name_size,
42                                int file_fd, int archive_fd, bool *write_error);
43 static bool write_header (const char *file_name, enum ustar_type, int size,
44                           int archive_fd, bool *write_error);
45
46 static bool do_write (int fd, const char *buffer, int size, bool *write_error);
47
48 static bool
49 make_tar_archive (const char *archive_name, char *files[], size_t file_cnt) 
50 {
51   static const char zeros[512];
52   int archive_fd;
53   bool success = true;
54   bool write_error = false;
55   size_t i;
56   
57   if (!create (archive_name, 0)) 
58     {
59       printf ("%s: create failed\n", archive_name);
60       return false;
61     }
62   archive_fd = open (archive_name);
63   if (archive_fd < 0)
64     {
65       printf ("%s: open failed\n", archive_name);
66       return false;
67     }
68
69   for (i = 0; i < file_cnt; i++) 
70     {
71       char file_name[128];
72       
73       strlcpy (file_name, files[i], sizeof file_name);
74       if (!archive_file (file_name, sizeof file_name,
75                          archive_fd, &write_error))
76         success = false;
77     }
78
79   if (!do_write (archive_fd, zeros, 512, &write_error)
80       || !do_write (archive_fd, zeros, 512, &write_error)) 
81     success = false;
82
83   close (archive_fd);
84
85   return success;
86 }
87
88 static bool
89 archive_file (char file_name[], size_t file_name_size,
90               int archive_fd, bool *write_error) 
91 {
92   int file_fd = open (file_name);
93   if (file_fd >= 0) 
94     {
95       bool success;
96
97       if (inumber (file_fd) != inumber (archive_fd)) 
98         {
99           if (!isdir (file_fd))
100             success = archive_ordinary_file (file_name, file_fd,
101                                              archive_fd, write_error);
102           else
103             success = archive_directory (file_name, file_name_size, file_fd,
104                                          archive_fd, write_error);      
105         }
106       else
107         {
108           /* Nothing to do: don't try to archive the archive file. */
109           success = true;
110         }
111   
112       close (file_fd);
113
114       return success;
115     }
116   else
117     {
118       printf ("%s: open failed\n", file_name);
119       return false;
120     }
121 }
122
123 static bool
124 archive_ordinary_file (const char *file_name, int file_fd,
125                        int archive_fd, bool *write_error)
126 {
127   bool read_error = false;
128   bool success = true;
129   int file_size = filesize (file_fd);
130
131   if (!write_header (file_name, USTAR_REGULAR, file_size,
132                      archive_fd, write_error))
133     return false;
134
135   while (file_size > 0) 
136     {
137       static char buf[512];
138       int chunk_size = file_size > 512 ? 512 : file_size;
139       int read_retval = read (file_fd, buf, chunk_size);
140       int bytes_read = read_retval > 0 ? read_retval : 0;
141
142       if (bytes_read != chunk_size && !read_error) 
143         {
144           printf ("%s: read error\n", file_name);
145           read_error = true;
146           success = false;
147         }
148
149       memset (buf + bytes_read, 0, 512 - bytes_read);
150       if (!do_write (archive_fd, buf, 512, write_error))
151         success = false;
152
153       file_size -= chunk_size;
154     }
155
156   return success;
157 }
158
159 static bool
160 archive_directory (char file_name[], size_t file_name_size, int file_fd,
161                    int archive_fd, bool *write_error)
162 {
163   size_t dir_len;
164   bool success = true;
165
166   dir_len = strlen (file_name);
167   if (dir_len + 1 + READDIR_MAX_LEN + 1 > file_name_size) 
168     {
169       printf ("%s: file name too long\n", file_name);
170       return false;
171     }
172
173   if (!write_header (file_name, USTAR_DIRECTORY, 0, archive_fd, write_error))
174     return false;
175       
176   file_name[dir_len] = '/';
177   while (readdir (file_fd, &file_name[dir_len + 1])) 
178     if (!archive_file (file_name, file_name_size, archive_fd, write_error))
179       success = false;
180   file_name[dir_len] = '\0';
181
182   return success;
183 }
184
185 static bool
186 write_header (const char *file_name, enum ustar_type type, int size,
187               int archive_fd, bool *write_error) 
188 {
189   static char header[512];
190   return (ustar_make_header (file_name, type, size, header)
191           && do_write (archive_fd, header, 512, write_error));
192 }
193
194 static bool
195 do_write (int fd, const char *buffer, int size, bool *write_error) 
196 {
197   if (write (fd, buffer, size) == size) 
198     return true;
199   else
200     {
201       if (!*write_error) 
202         {
203           printf ("error writing archive\n");
204           *write_error = true; 
205         }
206       return false; 
207     }
208 }