Branch data Line data Source code
1 : : /*
2 : : * Copyright 2015 Red Hat, Inc.
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 : : *
19 : : * Author: Matthias Clasen <mclasen@redhat.com>
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include <gio/gio.h>
25 : : #include <gi18n.h>
26 : :
27 : : #ifdef G_OS_WIN32
28 : : #include <io.h>
29 : : #endif
30 : :
31 : : #ifndef STDIN_FILENO
32 : : #define STDIN_FILENO 0
33 : : #endif
34 : :
35 : : #ifdef HAVE_UNISTD_H
36 : : #include <unistd.h>
37 : : #endif
38 : :
39 : : #include "gio-tool.h"
40 : :
41 : : static char *global_etag = NULL;
42 : : static gboolean backup = FALSE;
43 : : static gboolean create = FALSE;
44 : : static gboolean append = FALSE;
45 : : static gboolean priv = FALSE;
46 : : static gboolean replace_dest = FALSE;
47 : : static gboolean print_etag = FALSE;
48 : :
49 : : static const GOptionEntry entries[] =
50 : : {
51 : : { "backup", 'b', 0, G_OPTION_ARG_NONE, &backup, N_("Backup existing destination files"), NULL },
52 : : { "create", 'c', 0, G_OPTION_ARG_NONE, &create, N_("Only create if not existing"), NULL },
53 : : { "append", 'a', 0, G_OPTION_ARG_NONE, &append, N_("Append to end of file"), NULL },
54 : : { "private", 'p', 0, G_OPTION_ARG_NONE, &priv, N_("When creating, restrict access to the current user"), NULL },
55 : : { "unlink", 'u', 0, G_OPTION_ARG_NONE, &replace_dest, N_("When replacing, replace as if the destination did not exist"), NULL },
56 : : /* Translators: The "etag" is a token allowing to verify whether a file has been modified */
57 : : { "print-etag", 'v', 0, G_OPTION_ARG_NONE, &print_etag, N_("Print new etag at end"), NULL },
58 : : /* Translators: The "etag" is a token allowing to verify whether a file has been modified */
59 : : { "etag", 'e', 0, G_OPTION_ARG_STRING, &global_etag, N_("The etag of the file being overwritten"), N_("ETAG") },
60 : : G_OPTION_ENTRY_NULL
61 : : };
62 : :
63 : : /* 256k minus malloc overhead */
64 : : #define STREAM_BUFFER_SIZE (1024*256 - 2*sizeof(gpointer))
65 : :
66 : : static gboolean
67 : 0 : save (GFile *file)
68 : : {
69 : : GOutputStream *out;
70 : : GFileCreateFlags flags;
71 : : char *buffer;
72 : : gssize res;
73 : : gboolean close_res;
74 : : GError *error;
75 : : gboolean save_res;
76 : :
77 : 0 : error = NULL;
78 : :
79 : 0 : flags = priv ? G_FILE_CREATE_PRIVATE : G_FILE_CREATE_NONE;
80 : 0 : flags |= replace_dest ? G_FILE_CREATE_REPLACE_DESTINATION : 0;
81 : :
82 : 0 : if (create)
83 : 0 : out = (GOutputStream *)g_file_create (file, flags, NULL, &error);
84 : 0 : else if (append)
85 : 0 : out = (GOutputStream *)g_file_append_to (file, flags, NULL, &error);
86 : : else
87 : 0 : out = (GOutputStream *)g_file_replace (file, global_etag, backup, flags, NULL, &error);
88 : 0 : if (out == NULL)
89 : : {
90 : 0 : print_file_error (file, error->message);
91 : 0 : g_error_free (error);
92 : 0 : return FALSE;
93 : : }
94 : :
95 : 0 : buffer = g_malloc (STREAM_BUFFER_SIZE);
96 : 0 : save_res = TRUE;
97 : :
98 : : while (1)
99 : : {
100 : 0 : res = read (STDIN_FILENO, buffer, STREAM_BUFFER_SIZE);
101 : 0 : if (res > 0)
102 : : {
103 : 0 : g_output_stream_write_all (out, buffer, res, NULL, NULL, &error);
104 : 0 : if (error != NULL)
105 : : {
106 : 0 : save_res = FALSE;
107 : 0 : print_file_error (file, error->message);
108 : 0 : g_clear_error (&error);
109 : 0 : goto out;
110 : : }
111 : : }
112 : 0 : else if (res < 0)
113 : : {
114 : 0 : save_res = FALSE;
115 : 0 : print_error ("%s", _("Error reading from standard input"));
116 : 0 : break;
117 : : }
118 : 0 : else if (res == 0)
119 : 0 : break;
120 : : }
121 : :
122 : 0 : out:
123 : :
124 : 0 : close_res = g_output_stream_close (out, NULL, &error);
125 : 0 : if (!close_res)
126 : : {
127 : 0 : save_res = FALSE;
128 : 0 : print_file_error (file, error->message);
129 : 0 : g_error_free (error);
130 : : }
131 : :
132 : 0 : if (close_res && print_etag)
133 : : {
134 : : char *etag;
135 : 0 : etag = g_file_output_stream_get_etag (G_FILE_OUTPUT_STREAM (out));
136 : :
137 : 0 : if (etag)
138 : 0 : g_print ("Etag: %s\n", etag);
139 : : else
140 : : /* Translators: The "etag" is a token allowing to verify whether a file has been modified */
141 : 0 : g_print (_("Etag not available\n"));
142 : 0 : g_free (etag);
143 : : }
144 : :
145 : 0 : g_object_unref (out);
146 : 0 : g_free (buffer);
147 : :
148 : 0 : return save_res;
149 : : }
150 : :
151 : : int
152 : 0 : handle_save (int argc, char *argv[], gboolean do_help)
153 : : {
154 : : GOptionContext *context;
155 : 0 : GError *error = NULL;
156 : : GFile *file;
157 : : gboolean res;
158 : :
159 : 0 : g_set_prgname ("gio save");
160 : :
161 : : /* Translators: commandline placeholder */
162 : 0 : context = g_option_context_new (_("DESTINATION"));
163 : 0 : g_option_context_set_help_enabled (context, FALSE);
164 : 0 : g_option_context_set_summary (context,
165 : 0 : _("Read from standard input and save to DEST."));
166 : 0 : g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
167 : :
168 : 0 : if (do_help)
169 : : {
170 : 0 : show_help (context, NULL);
171 : 0 : g_option_context_free (context);
172 : 0 : return 0;
173 : : }
174 : :
175 : 0 : if (!g_option_context_parse (context, &argc, &argv, &error))
176 : : {
177 : 0 : show_help (context, error->message);
178 : 0 : g_error_free (error);
179 : 0 : g_option_context_free (context);
180 : 0 : return 1;
181 : : }
182 : :
183 : 0 : if (argc < 2)
184 : : {
185 : 0 : show_help (context, _("No destination given"));
186 : 0 : g_option_context_free (context);
187 : 0 : return 1;
188 : : }
189 : :
190 : 0 : if (argc > 2)
191 : : {
192 : 0 : show_help (context, _("Too many arguments"));
193 : 0 : g_option_context_free (context);
194 : 0 : return 1;
195 : : }
196 : :
197 : 0 : g_option_context_free (context);
198 : :
199 : 0 : file = g_file_new_for_commandline_arg (argv[1]);
200 : 0 : res = save (file);
201 : 0 : g_object_unref (file);
202 : :
203 : 0 : return res ? 0 : 2;
204 : : }
|