Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: mozilla/security/nss/lib/ckfw/slot.c

Issue 14249009: Change the NSS and NSPR source tree to the new directory structure to be (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « mozilla/security/nss/lib/ckfw/sessobj.c ('k') | mozilla/security/nss/lib/ckfw/token.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #ifdef DEBUG
6 static const char CVS_ID[] = "@(#) $RCSfile: slot.c,v $ $Revision: 1.8 $ $Date: 2012/04/25 14:49:28 $";
7 #endif /* DEBUG */
8
9 /*
10 * slot.c
11 *
12 * This file implements the NSSCKFWSlot type and methods.
13 */
14
15 #ifndef CK_T
16 #include "ck.h"
17 #endif /* CK_T */
18
19 /*
20 * NSSCKFWSlot
21 *
22 * -- create/destroy --
23 * nssCKFWSlot_Create
24 * nssCKFWSlot_Destroy
25 *
26 * -- public accessors --
27 * NSSCKFWSlot_GetMDSlot
28 * NSSCKFWSlot_GetFWInstance
29 * NSSCKFWSlot_GetMDInstance
30 *
31 * -- implement public accessors --
32 * nssCKFWSlot_GetMDSlot
33 * nssCKFWSlot_GetFWInstance
34 * nssCKFWSlot_GetMDInstance
35 *
36 * -- private accessors --
37 * nssCKFWSlot_GetSlotID
38 * nssCKFWSlot_ClearToken
39 *
40 * -- module fronts --
41 * nssCKFWSlot_GetSlotDescription
42 * nssCKFWSlot_GetManufacturerID
43 * nssCKFWSlot_GetTokenPresent
44 * nssCKFWSlot_GetRemovableDevice
45 * nssCKFWSlot_GetHardwareSlot
46 * nssCKFWSlot_GetHardwareVersion
47 * nssCKFWSlot_GetFirmwareVersion
48 * nssCKFWSlot_InitToken
49 * nssCKFWSlot_GetToken
50 */
51
52 struct NSSCKFWSlotStr {
53 NSSCKFWMutex *mutex;
54 NSSCKMDSlot *mdSlot;
55 NSSCKFWInstance *fwInstance;
56 NSSCKMDInstance *mdInstance;
57 CK_SLOT_ID slotID;
58
59 /*
60 * Everything above is set at creation time, and then not modified.
61 * The invariants the mutex protects are:
62 *
63 * 1) Each of the cached descriptions (versions, etc.) are in an
64 * internally consistant state.
65 *
66 * 2) The fwToken points to the token currently in the slot, and
67 * it is in a consistant state.
68 *
69 * Note that the calls accessing the cached descriptions will
70 * call the NSSCKMDSlot methods with the mutex locked. Those
71 * methods may then call the public NSSCKFWSlot routines. Those
72 * public routines only access the constant data above, so there's
73 * no problem. But be careful if you add to this object; mutexes
74 * are in general not reentrant, so don't create deadlock situations.
75 */
76
77 NSSUTF8 *slotDescription;
78 NSSUTF8 *manufacturerID;
79 CK_VERSION hardwareVersion;
80 CK_VERSION firmwareVersion;
81 NSSCKFWToken *fwToken;
82 };
83
84 #ifdef DEBUG
85 /*
86 * But first, the pointer-tracking stuff.
87 *
88 * NOTE: the pointer-tracking support in NSS/base currently relies
89 * upon NSPR's CallOnce support. That, however, relies upon NSPR's
90 * locking, which is tied into the runtime. We need a pointer-tracker
91 * implementation that uses the locks supplied through C_Initialize.
92 * That support, however, can be filled in later. So for now, I'll
93 * just do this routines as no-ops.
94 */
95
96 static CK_RV
97 slot_add_pointer
98 (
99 const NSSCKFWSlot *fwSlot
100 )
101 {
102 return CKR_OK;
103 }
104
105 static CK_RV
106 slot_remove_pointer
107 (
108 const NSSCKFWSlot *fwSlot
109 )
110 {
111 return CKR_OK;
112 }
113
114 NSS_IMPLEMENT CK_RV
115 nssCKFWSlot_verifyPointer
116 (
117 const NSSCKFWSlot *fwSlot
118 )
119 {
120 return CKR_OK;
121 }
122
123 #endif /* DEBUG */
124
125 /*
126 * nssCKFWSlot_Create
127 *
128 */
129 NSS_IMPLEMENT NSSCKFWSlot *
130 nssCKFWSlot_Create
131 (
132 NSSCKFWInstance *fwInstance,
133 NSSCKMDSlot *mdSlot,
134 CK_SLOT_ID slotID,
135 CK_RV *pError
136 )
137 {
138 NSSCKFWSlot *fwSlot;
139 NSSCKMDInstance *mdInstance;
140 NSSArena *arena;
141
142 #ifdef NSSDEBUG
143 if (!pError) {
144 return (NSSCKFWSlot *)NULL;
145 }
146
147 *pError = nssCKFWInstance_verifyPointer(fwInstance);
148 if( CKR_OK != *pError ) {
149 return (NSSCKFWSlot *)NULL;
150 }
151 #endif /* NSSDEBUG */
152
153 mdInstance = nssCKFWInstance_GetMDInstance(fwInstance);
154 if (!mdInstance) {
155 *pError = CKR_GENERAL_ERROR;
156 return (NSSCKFWSlot *)NULL;
157 }
158
159 arena = nssCKFWInstance_GetArena(fwInstance, pError);
160 if (!arena) {
161 if( CKR_OK == *pError ) {
162 *pError = CKR_GENERAL_ERROR;
163 }
164 }
165
166 fwSlot = nss_ZNEW(arena, NSSCKFWSlot);
167 if (!fwSlot) {
168 *pError = CKR_HOST_MEMORY;
169 return (NSSCKFWSlot *)NULL;
170 }
171
172 fwSlot->mdSlot = mdSlot;
173 fwSlot->fwInstance = fwInstance;
174 fwSlot->mdInstance = mdInstance;
175 fwSlot->slotID = slotID;
176
177 fwSlot->mutex = nssCKFWInstance_CreateMutex(fwInstance, arena, pError);
178 if (!fwSlot->mutex) {
179 if( CKR_OK == *pError ) {
180 *pError = CKR_GENERAL_ERROR;
181 }
182 (void)nss_ZFreeIf(fwSlot);
183 return (NSSCKFWSlot *)NULL;
184 }
185
186 if (mdSlot->Initialize) {
187 *pError = CKR_OK;
188 *pError = mdSlot->Initialize(mdSlot, fwSlot, mdInstance, fwInstance);
189 if( CKR_OK != *pError ) {
190 (void)nssCKFWMutex_Destroy(fwSlot->mutex);
191 (void)nss_ZFreeIf(fwSlot);
192 return (NSSCKFWSlot *)NULL;
193 }
194 }
195
196 #ifdef DEBUG
197 *pError = slot_add_pointer(fwSlot);
198 if( CKR_OK != *pError ) {
199 if (mdSlot->Destroy) {
200 mdSlot->Destroy(mdSlot, fwSlot, mdInstance, fwInstance);
201 }
202
203 (void)nssCKFWMutex_Destroy(fwSlot->mutex);
204 (void)nss_ZFreeIf(fwSlot);
205 return (NSSCKFWSlot *)NULL;
206 }
207 #endif /* DEBUG */
208
209 return fwSlot;
210 }
211
212 /*
213 * nssCKFWSlot_Destroy
214 *
215 */
216 NSS_IMPLEMENT CK_RV
217 nssCKFWSlot_Destroy
218 (
219 NSSCKFWSlot *fwSlot
220 )
221 {
222 CK_RV error = CKR_OK;
223
224 #ifdef NSSDEBUG
225 error = nssCKFWSlot_verifyPointer(fwSlot);
226 if( CKR_OK != error ) {
227 return error;
228 }
229 #endif /* NSSDEBUG */
230 if (fwSlot->fwToken) {
231 nssCKFWToken_Destroy(fwSlot->fwToken);
232 }
233
234 (void)nssCKFWMutex_Destroy(fwSlot->mutex);
235
236 if (fwSlot->mdSlot->Destroy) {
237 fwSlot->mdSlot->Destroy(fwSlot->mdSlot, fwSlot,
238 fwSlot->mdInstance, fwSlot->fwInstance);
239 }
240
241 #ifdef DEBUG
242 error = slot_remove_pointer(fwSlot);
243 #endif /* DEBUG */
244 (void)nss_ZFreeIf(fwSlot);
245 return error;
246 }
247
248 /*
249 * nssCKFWSlot_GetMDSlot
250 *
251 */
252 NSS_IMPLEMENT NSSCKMDSlot *
253 nssCKFWSlot_GetMDSlot
254 (
255 NSSCKFWSlot *fwSlot
256 )
257 {
258 #ifdef NSSDEBUG
259 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
260 return (NSSCKMDSlot *)NULL;
261 }
262 #endif /* NSSDEBUG */
263
264 return fwSlot->mdSlot;
265 }
266
267 /*
268 * nssCKFWSlot_GetFWInstance
269 *
270 */
271
272 NSS_IMPLEMENT NSSCKFWInstance *
273 nssCKFWSlot_GetFWInstance
274 (
275 NSSCKFWSlot *fwSlot
276 )
277 {
278 #ifdef NSSDEBUG
279 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
280 return (NSSCKFWInstance *)NULL;
281 }
282 #endif /* NSSDEBUG */
283
284 return fwSlot->fwInstance;
285 }
286
287 /*
288 * nssCKFWSlot_GetMDInstance
289 *
290 */
291
292 NSS_IMPLEMENT NSSCKMDInstance *
293 nssCKFWSlot_GetMDInstance
294 (
295 NSSCKFWSlot *fwSlot
296 )
297 {
298 #ifdef NSSDEBUG
299 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
300 return (NSSCKMDInstance *)NULL;
301 }
302 #endif /* NSSDEBUG */
303
304 return fwSlot->mdInstance;
305 }
306
307 /*
308 * nssCKFWSlot_GetSlotID
309 *
310 */
311 NSS_IMPLEMENT CK_SLOT_ID
312 nssCKFWSlot_GetSlotID
313 (
314 NSSCKFWSlot *fwSlot
315 )
316 {
317 #ifdef NSSDEBUG
318 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
319 return (CK_SLOT_ID)0;
320 }
321 #endif /* NSSDEBUG */
322
323 return fwSlot->slotID;
324 }
325
326 /*
327 * nssCKFWSlot_GetSlotDescription
328 *
329 */
330 NSS_IMPLEMENT CK_RV
331 nssCKFWSlot_GetSlotDescription
332 (
333 NSSCKFWSlot *fwSlot,
334 CK_CHAR slotDescription[64]
335 )
336 {
337 CK_RV error = CKR_OK;
338
339 #ifdef NSSDEBUG
340 if( (CK_CHAR_PTR)NULL == slotDescription ) {
341 return CKR_ARGUMENTS_BAD;
342 }
343
344 error = nssCKFWSlot_verifyPointer(fwSlot);
345 if( CKR_OK != error ) {
346 return error;
347 }
348 #endif /* NSSDEBUG */
349
350 error = nssCKFWMutex_Lock(fwSlot->mutex);
351 if( CKR_OK != error ) {
352 return error;
353 }
354
355 if (!fwSlot->slotDescription) {
356 if (fwSlot->mdSlot->GetSlotDescription) {
357 fwSlot->slotDescription = fwSlot->mdSlot->GetSlotDescription(
358 fwSlot->mdSlot, fwSlot, fwSlot->mdInstance,
359 fwSlot->fwInstance, &error);
360 if ((!fwSlot->slotDescription) && (CKR_OK != error)) {
361 goto done;
362 }
363 } else {
364 fwSlot->slotDescription = (NSSUTF8 *) "";
365 }
366 }
367
368 (void)nssUTF8_CopyIntoFixedBuffer(fwSlot->slotDescription, (char *)slotDescrip tion, 64, ' ');
369 error = CKR_OK;
370
371 done:
372 (void)nssCKFWMutex_Unlock(fwSlot->mutex);
373 return error;
374 }
375
376 /*
377 * nssCKFWSlot_GetManufacturerID
378 *
379 */
380 NSS_IMPLEMENT CK_RV
381 nssCKFWSlot_GetManufacturerID
382 (
383 NSSCKFWSlot *fwSlot,
384 CK_CHAR manufacturerID[32]
385 )
386 {
387 CK_RV error = CKR_OK;
388
389 #ifdef NSSDEBUG
390 if( (CK_CHAR_PTR)NULL == manufacturerID ) {
391 return CKR_ARGUMENTS_BAD;
392 }
393
394 error = nssCKFWSlot_verifyPointer(fwSlot);
395 if( CKR_OK != error ) {
396 return error;
397 }
398 #endif /* NSSDEBUG */
399
400 error = nssCKFWMutex_Lock(fwSlot->mutex);
401 if( CKR_OK != error ) {
402 return error;
403 }
404
405 if (!fwSlot->manufacturerID) {
406 if (fwSlot->mdSlot->GetManufacturerID) {
407 fwSlot->manufacturerID = fwSlot->mdSlot->GetManufacturerID(
408 fwSlot->mdSlot, fwSlot, fwSlot->mdInstance,
409 fwSlot->fwInstance, &error);
410 if ((!fwSlot->manufacturerID) && (CKR_OK != error)) {
411 goto done;
412 }
413 } else {
414 fwSlot->manufacturerID = (NSSUTF8 *) "";
415 }
416 }
417
418 (void)nssUTF8_CopyIntoFixedBuffer(fwSlot->manufacturerID, (char *)manufacturer ID, 32, ' ');
419 error = CKR_OK;
420
421 done:
422 (void)nssCKFWMutex_Unlock(fwSlot->mutex);
423 return error;
424 }
425
426 /*
427 * nssCKFWSlot_GetTokenPresent
428 *
429 */
430 NSS_IMPLEMENT CK_BBOOL
431 nssCKFWSlot_GetTokenPresent
432 (
433 NSSCKFWSlot *fwSlot
434 )
435 {
436 #ifdef NSSDEBUG
437 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
438 return CK_FALSE;
439 }
440 #endif /* NSSDEBUG */
441
442 if (!fwSlot->mdSlot->GetTokenPresent) {
443 return CK_TRUE;
444 }
445
446 return fwSlot->mdSlot->GetTokenPresent(fwSlot->mdSlot, fwSlot,
447 fwSlot->mdInstance, fwSlot->fwInstance);
448 }
449
450 /*
451 * nssCKFWSlot_GetRemovableDevice
452 *
453 */
454 NSS_IMPLEMENT CK_BBOOL
455 nssCKFWSlot_GetRemovableDevice
456 (
457 NSSCKFWSlot *fwSlot
458 )
459 {
460 #ifdef NSSDEBUG
461 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
462 return CK_FALSE;
463 }
464 #endif /* NSSDEBUG */
465
466 if (!fwSlot->mdSlot->GetRemovableDevice) {
467 return CK_FALSE;
468 }
469
470 return fwSlot->mdSlot->GetRemovableDevice(fwSlot->mdSlot, fwSlot,
471 fwSlot->mdInstance, fwSlot->fwInstance);
472 }
473
474 /*
475 * nssCKFWSlot_GetHardwareSlot
476 *
477 */
478 NSS_IMPLEMENT CK_BBOOL
479 nssCKFWSlot_GetHardwareSlot
480 (
481 NSSCKFWSlot *fwSlot
482 )
483 {
484 #ifdef NSSDEBUG
485 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
486 return CK_FALSE;
487 }
488 #endif /* NSSDEBUG */
489
490 if (!fwSlot->mdSlot->GetHardwareSlot) {
491 return CK_FALSE;
492 }
493
494 return fwSlot->mdSlot->GetHardwareSlot(fwSlot->mdSlot, fwSlot,
495 fwSlot->mdInstance, fwSlot->fwInstance);
496 }
497
498 /*
499 * nssCKFWSlot_GetHardwareVersion
500 *
501 */
502 NSS_IMPLEMENT CK_VERSION
503 nssCKFWSlot_GetHardwareVersion
504 (
505 NSSCKFWSlot *fwSlot
506 )
507 {
508 CK_VERSION rv;
509
510 #ifdef NSSDEBUG
511 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
512 rv.major = rv.minor = 0;
513 return rv;
514 }
515 #endif /* NSSDEBUG */
516
517 if( CKR_OK != nssCKFWMutex_Lock(fwSlot->mutex) ) {
518 rv.major = rv.minor = 0;
519 return rv;
520 }
521
522 if( (0 != fwSlot->hardwareVersion.major) ||
523 (0 != fwSlot->hardwareVersion.minor) ) {
524 rv = fwSlot->hardwareVersion;
525 goto done;
526 }
527
528 if (fwSlot->mdSlot->GetHardwareVersion) {
529 fwSlot->hardwareVersion = fwSlot->mdSlot->GetHardwareVersion(
530 fwSlot->mdSlot, fwSlot, fwSlot->mdInstance, fwSlot->fwInstance);
531 } else {
532 fwSlot->hardwareVersion.major = 0;
533 fwSlot->hardwareVersion.minor = 1;
534 }
535
536 rv = fwSlot->hardwareVersion;
537 done:
538 (void)nssCKFWMutex_Unlock(fwSlot->mutex);
539 return rv;
540 }
541
542 /*
543 * nssCKFWSlot_GetFirmwareVersion
544 *
545 */
546 NSS_IMPLEMENT CK_VERSION
547 nssCKFWSlot_GetFirmwareVersion
548 (
549 NSSCKFWSlot *fwSlot
550 )
551 {
552 CK_VERSION rv;
553
554 #ifdef NSSDEBUG
555 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
556 rv.major = rv.minor = 0;
557 return rv;
558 }
559 #endif /* NSSDEBUG */
560
561 if( CKR_OK != nssCKFWMutex_Lock(fwSlot->mutex) ) {
562 rv.major = rv.minor = 0;
563 return rv;
564 }
565
566 if( (0 != fwSlot->firmwareVersion.major) ||
567 (0 != fwSlot->firmwareVersion.minor) ) {
568 rv = fwSlot->firmwareVersion;
569 goto done;
570 }
571
572 if (fwSlot->mdSlot->GetFirmwareVersion) {
573 fwSlot->firmwareVersion = fwSlot->mdSlot->GetFirmwareVersion(
574 fwSlot->mdSlot, fwSlot, fwSlot->mdInstance, fwSlot->fwInstance);
575 } else {
576 fwSlot->firmwareVersion.major = 0;
577 fwSlot->firmwareVersion.minor = 1;
578 }
579
580 rv = fwSlot->firmwareVersion;
581 done:
582 (void)nssCKFWMutex_Unlock(fwSlot->mutex);
583 return rv;
584 }
585
586 /*
587 * nssCKFWSlot_GetToken
588 *
589 */
590 NSS_IMPLEMENT NSSCKFWToken *
591 nssCKFWSlot_GetToken
592 (
593 NSSCKFWSlot *fwSlot,
594 CK_RV *pError
595 )
596 {
597 NSSCKMDToken *mdToken;
598 NSSCKFWToken *fwToken;
599
600 #ifdef NSSDEBUG
601 if (!pError) {
602 return (NSSCKFWToken *)NULL;
603 }
604
605 *pError = nssCKFWSlot_verifyPointer(fwSlot);
606 if( CKR_OK != *pError ) {
607 return (NSSCKFWToken *)NULL;
608 }
609 #endif /* NSSDEBUG */
610
611 *pError = nssCKFWMutex_Lock(fwSlot->mutex);
612 if( CKR_OK != *pError ) {
613 return (NSSCKFWToken *)NULL;
614 }
615
616 if (!fwSlot->fwToken) {
617 if (!fwSlot->mdSlot->GetToken) {
618 *pError = CKR_GENERAL_ERROR;
619 fwToken = (NSSCKFWToken *)NULL;
620 goto done;
621 }
622
623 mdToken = fwSlot->mdSlot->GetToken(fwSlot->mdSlot, fwSlot,
624 fwSlot->mdInstance, fwSlot->fwInstance, pError);
625 if (!mdToken) {
626 if( CKR_OK == *pError ) {
627 *pError = CKR_GENERAL_ERROR;
628 }
629 return (NSSCKFWToken *)NULL;
630 }
631
632 fwToken = nssCKFWToken_Create(fwSlot, mdToken, pError);
633 fwSlot->fwToken = fwToken;
634 } else {
635 fwToken = fwSlot->fwToken;
636 }
637
638 done:
639 (void)nssCKFWMutex_Unlock(fwSlot->mutex);
640 return fwToken;
641 }
642
643 /*
644 * nssCKFWSlot_ClearToken
645 *
646 */
647 NSS_IMPLEMENT void
648 nssCKFWSlot_ClearToken
649 (
650 NSSCKFWSlot *fwSlot
651 )
652 {
653 #ifdef NSSDEBUG
654 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
655 return;
656 }
657 #endif /* NSSDEBUG */
658
659 if( CKR_OK != nssCKFWMutex_Lock(fwSlot->mutex) ) {
660 /* Now what? */
661 return;
662 }
663
664 fwSlot->fwToken = (NSSCKFWToken *)NULL;
665 (void)nssCKFWMutex_Unlock(fwSlot->mutex);
666 return;
667 }
668
669 /*
670 * NSSCKFWSlot_GetMDSlot
671 *
672 */
673
674 NSS_IMPLEMENT NSSCKMDSlot *
675 NSSCKFWSlot_GetMDSlot
676 (
677 NSSCKFWSlot *fwSlot
678 )
679 {
680 #ifdef DEBUG
681 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
682 return (NSSCKMDSlot *)NULL;
683 }
684 #endif /* DEBUG */
685
686 return nssCKFWSlot_GetMDSlot(fwSlot);
687 }
688
689 /*
690 * NSSCKFWSlot_GetFWInstance
691 *
692 */
693
694 NSS_IMPLEMENT NSSCKFWInstance *
695 NSSCKFWSlot_GetFWInstance
696 (
697 NSSCKFWSlot *fwSlot
698 )
699 {
700 #ifdef DEBUG
701 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
702 return (NSSCKFWInstance *)NULL;
703 }
704 #endif /* DEBUG */
705
706 return nssCKFWSlot_GetFWInstance(fwSlot);
707 }
708
709 /*
710 * NSSCKFWSlot_GetMDInstance
711 *
712 */
713
714 NSS_IMPLEMENT NSSCKMDInstance *
715 NSSCKFWSlot_GetMDInstance
716 (
717 NSSCKFWSlot *fwSlot
718 )
719 {
720 #ifdef DEBUG
721 if( CKR_OK != nssCKFWSlot_verifyPointer(fwSlot) ) {
722 return (NSSCKMDInstance *)NULL;
723 }
724 #endif /* DEBUG */
725
726 return nssCKFWSlot_GetMDInstance(fwSlot);
727 }
OLDNEW
« no previous file with comments | « mozilla/security/nss/lib/ckfw/sessobj.c ('k') | mozilla/security/nss/lib/ckfw/token.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698